Reputation: 485
I'm looking for C Sharp example of abstract method with general prototype that the derived override methods can receive different structure of parameters.
example from C++
class IBase {
public:
virtual void method(void * pParameters) = 0;
}
class CDerivedA : public IBase {
public:
struct S_A {
char a;
short b;
}
virtual void method(void * pParameters);
}
void CDerivedA::method(void * pParameters) {
S_A * pSa = (S_A *)pParameters;
pSa->a
pSa->b
}
class CDerivedB : public IBase {
public:
struct S_B {
long c;
float d;
double e;
}
virtual void method(void * pParameters);
}
void CDerivedB::method(void * pParameters) {
S_B * pSb = (S_B *)pParameters;
pSb->c
pSb->d
pSb->e
}
execution speed is very important so I prefer pass by reference.
I found 2 options to implement this in C#: 1.
interface IBase {
void method(object parameters);
}
class CDerivedA : IBase {
void method(object parameters) {
// cast to use the parameters
user obj = (user)parameters;
...
}
}
class CDerivedB : IBase {
void method(object parameters) {
// cast to use the parameters
point obj = (point)parameters;
...
}
}
2.
interface IBase {
void method(dynamic parameters);
}
class CDerivedA : IBase {
// directly use the parameters
void method(dynamic parameters) {
...
}
}
class CDerivedB : IBase {
// directly use the parameters
void method(dynamic parameters) {
...
}
}
witch is better / faster?
Upvotes: 0
Views: 1399
Reputation: 3928
Because C# is a managed language, there is no such thing as void*
(which was never really a good idea even in C++). You have two options in C#: pass an 'object' or use generics. An object has to be cast to the appropriate type to be used as anything other than a black box. Generics (the less powerful C# version of templates) are usually the way to go.
If you need to pass multiple parameters, you can use a C# Tuple
(similar to a C void*
array) or a params
object array (similar to a C varargs).
In the absence of a good example of why this would be useful (if that's possible) this looks like a bad design.
I can see from the comments that there is a lot of confusion on this topic, so let me be absolutely clear:
class
and struct
in C# and C++ are very different. In C++, the distinction is about construction and public/private access to fields. In C#, the distinction is about how they are handled when passed as parameters.
In C# when you declare a class and pass 'the class' (an instance of the class, actually) into a function, you are really passing a reference to the class instance into the function. There is no way to pass the class instance itself into the function, as you can in C++. Unlike C++, In C#, the function you call can modify the data in the class instance and such changes will be seen by the caller, because in C++ a copy constructor is called and the class instance data is actually copied onto the stack, but in C#, classes are reference types.
Here are some examples, assuming C
is a class
and S
is a struct
in both languages:
In C++:
void func (C c)
{
c.value = true; // This change will NOT be seen by the caller because the class was passed by value
}
void func (C* c)
{
c->value = true; // This change WILL be seen by the caller because the class was passed by reference (pointer in this case, though the distinction is only syntactic)
c = new C(); // This new instance will not be seen by the caller and will never be destroyed or freed
}
void func (C& c)
{
c.value = true; // This change WILL be seen by the caller because the class was passed by reference
}
void func (C** c)
{
(*c)->value = true; // This change will only be seen by the caller if they kept another pointer (reference) to the instance, because the next statement will overwrite the pointer whose pointer was passed into this function
*c = new C(); // A new instance of C WILL be seen by the caller because the pointer to the class was passed by reference (pointer)
}
void func (S s)
{
s.value = true; // This change will NOT be seen by the caller because the struct was passed by value
}
void func (S* s)
{
s->value = true; // This change WILL be seen by the caller because the struct was passed by reference (pointer)
s = new S(); // This new instance will not be seen by the caller and will never be destroyed or freed
}
void func (S& s)
{
s.value = true; // This change WILL be seen by the caller because the struct was passed by reference
}
void func (S** s)
{
(*s)->value = true; // This change will only be seen by the caller if they kept another pointer (reference) to the instance, because the next statement will overwrite the pointer whose pointer was passed into this function
*s = new S(); // A new instance of S WILL be seen by the caller because the pointer to the struct was passed by reference (pointer)
}
And in C#:
void func (C c)
{
c.value = true; // This change will be seen by the caller because the class was passed by reference
}
void func (ref C c)
{
c.value = true; // This change will only be seen by the caller if they kept another reference to the class instance other than the one they passed by reference to this function, because the next statement will overwrite the reference whose reference was passed into this function
c = new C(); // A new instance of C WILL be seen by the caller because the reference to the class was passed (by reference)
}
void func (S s)
{
s.value = true; // This change will NOT be seen by the caller because the struct was passed by value
}
void func (ref S s)
{
s.value = true; // This change will only be seen by the caller if they kept another reference to the struct instance other than the one they passed by reference to this function, because the next statement will overwrite the reference whose reference was passed into this function. I think this would require boxing the original struct instance.
s = new S(); // A new instance of S WILL be seen by the caller because the struct was passed by reference
}
To pass actual data (not references/pointers) by value in C#, the data must be declared as a struct
. Please see Microsoft's explanation of structs vs. classes in C# for more information.
Upvotes: 3