0

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?

teach me
  • 453
  • 5
  • 20
  • It’s quite unclear to me what you’re asking. You’ve shown a C++ code (with some very questionable behaviour) – how does that relate to your C# question? However, passing classes by reference is *not* faster than passing them by value in C#. – Konrad Rudolph Jan 31 '15 at 22:42
  • 1
    @Konrad: How do you even pass a C# class by value? – James Jan 31 '15 at 22:48
  • It's usually a very bad idea to port 1:1 when moving to a different language. Can you show a C# example so we can see what have you actually tried to do and didn't work as expected? – walther Jan 31 '15 at 22:49
  • @James That's what happens by default, unless you specify the parameter as `ref`. – Konrad Rudolph Jan 31 '15 at 22:53
  • 1
    @Konrad: No, it's not. `ref` allows the function being called to change the reference to point to another instance, which is the same as passing a `void**` in C++. In C#, only a pointer is passed in either case, and the values within the class can be changed by the called function in either case. Pass by value means that the called function cannot change the value seen by the caller. In C# pass-by-value is done by declaring the 'class' with `struct`. – James Jan 31 '15 at 22:59
  • 3
    @James No, you're really wrong here. You are confusing passing *references* to objects *by value* (which is what C# is doing) and passing values by reference. If that explanation isn't convincing you, there are more thorough explanations of this here on Stack Overflow. – Konrad Rudolph Jan 31 '15 at 23:05
  • @Konrad: Given your rep, I'm sure we're just miscommunicating here. I've been writing C# every day for ten years now, after writing C++ every day for the previous ten years. C# classes are *reference types*. As such, they *cannot* be passed by value. A *reference to a class* can be passed by value (this is the default behavior), but a class instance cannot be passed by value because a class is a reference type (see C# documentation reference in the answer below). – James Jan 31 '15 at 23:21
  • 1
    @James This is simply a terminology question. Passing class instances without `ref` in C# is called "by value" (it's a firmly established convention). What matters is how the variable is passed into the method, not whether it's itself a reference or not. This is fundamentally different from passing variables by reference, be it in C# or C++. – Konrad Rudolph Jan 31 '15 at 23:41
  • @James, the fact you `pass a reference` doesn't mean you're `passing by reference`. There's a slight difference between those two. See Jon Skeet's article http://jonskeet.uk/csharp/parameters.html to clear up the confusion... – walther Jan 31 '15 at 23:58
  • @Konrad, I may have been using the wrong terminology for the past ten years, then. Can you point me to a reference to that "firmly established convention?" If that is indeed the established convention, I think it's a *terrible* convention, as it is very confusing to users of other languages. I can understand using the phrase *reference passed by value*, but to me *pass by value* has always meant that the *data* was *passed by value*, not that the reference/pointer was passed by value. Pointers are confusing enough without introducing confusing terminology. – James Jan 31 '15 at 23:58
  • @James Here’s what the MSDN says: https://msdn.microsoft.com/en-us/library/s6938f28.aspx – however, the MSDN isn’t actually a great definitive reference, since it gets these things occasionally wrong. A better source is [Wikipedia](http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_value) (read the *whole* article starting at the linked paragraph). Finally, to see that it’s common use, it’s enough to google. For instance, [here’s a related discussion for Java](http://stackoverflow.com/q/40480/1968). – Konrad Rudolph Feb 01 '15 at 00:16
  • Why the downvotes? This is actually quite a relevant question for a person coming from C++ to C#. Upvoted. – John Castleman Feb 01 '15 at 00:39
  • @Konrad: None of those articles talk about 'passing classes by reference' as you did, which is what caused my confusion. 'Classes' cannot be passed by reference, indeed they cannot be passed at all. Instances of classes can be passed by reference or by value. Variables can be passed by reference or by value, and those variables may refer to instances or to references. The articles you referenced are all fairly clear on that, and the Java discussion in the first (very highly voted) comment makes it clear that for C people (like OP), you need to be very clear when using the word 'reference'. – James Feb 01 '15 at 00:44
  • @Konrad: ...I should have been more clear on that in my first comment. In any case, I think it's a potato-potato issue at this point, as my answer below and the references you and I have given should make things very clear to any readers. Cheers! – James Feb 01 '15 at 00:46

1 Answers1

3

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.

James
  • 3,551
  • 1
  • 28
  • 38
  • 3
    In C# *references* are passed to methods *by value* unless they are explicitly passed by reference with either the `ref` or `out` keywords. – Preston Guillot Jan 31 '15 at 23:09
  • @Preston: correct. I've edited to hopefully clarify any misunderstanding. In C#, classes are *always* references and structs are usually by value (unless using the `ref` or `out` keyword, and even then you have to be careful). In C++, both are by value by default (which is why most C++ functions take a *pointer to a class* in the parameters). – James Jan 31 '15 at 23:47