简体   繁体   中英

C++ templates versus C# generic method with various parameters

in C++, this works.

template<class T> void func(T t)
{ t.method(); }

How to implement this in C#? Here is what I tried but it doesn't work.

void func<T>(T t)
{ t.method(); }

Or it is impossible to do this in C#?

The following should work

public static class MyClass
{
  public static void MyMethod<T>(T t) where T : class
  {
     t.ToString(); // Note: for this to work we need to KNOW the type which defines `method`.
  }
}

as well as this:

public class MyBase
{
   void Method();
}

public static class MyClassForBase
{
  public static void MyMethod<T>(T t) where T : MyBase
  {
     t.Method(); // Note: anything from MyBase is now available
  }
}

Last, but not least, you can use late-binding like so

public static class MyClassDynamic
{
  public static void MyMethod(dynamic t)
  {
     t.Method(); // Note: if t doesn't have a `Method` defined, the code will crush-n-burn at runtime
  }
}

In a method that takes a generic parameter, you can only call methods on that parameter that the compiler knows will be there.

In your example:

void func<T>(T t)
{
    t.method();
}

the compiler does not know that the method method exists, so this will not work.

You can tell the compiler which methods will be available by using constraints . For example, if the method is defined on an interface then you can constrain it correctly using a where clause like this:

pubic interface IClassWithMethod
{
    void method();
}

void func<T>(T t) where T : IClassWithMethod
{
    t.method();
}

Generics in C# are NOT the same as templates in C++. C++ templates are essentially marcos that are applied to code at compile-time depending on what types they are used with. So if you tried to use your template on a class that did not have a .method() method, it would fail at compile time.

C# generics instead require that whatever type T could be must define any methods and properties that the generic method uses. So if you have a base type or interface that defines a .method() method, you would constrain your generic method to that type:

void func<T>(T t) where T:IHaveMethod
{ t.method(); }

So long as the IHaveMethod interface defines method() , the generic function will compile. Note that in your specific example the generic method is useless since you can just call method on the interface type.

Where generics is more useful is when you want the return type to be based on the input type:

T func<T>(T t) where T:IHaveMethod
{ t.method(); return t;}

Now, not only does method gets called, but the return type is exactly the type of the generic argument, not just an IHaveMethod , which might limit what you can do with the return without casting.

Bottom line, don't think of generics the same way you think of C++ templates. THere are very fundamental differences that will make it harder for you to see when and where generics can/should be used.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM