简体   繁体   中英

C#: Call overloaded method in external assembly from generic

I have a project that references a 3rd party c# assembly containing several overloaded instance methods. I want to invoke one of these methods via a generic in my code, calling the instance method whose parameter type matches the type of the generic:

void GetVal<T>(ref T val)
{
    VendorLib v = new VendorLib();
    v.GetVal(ref val); 
}

// error CS1503: Argument 1: cannot convert from 'ref T' to 'ref bool'

The closest I have come is through the use of a dynamic variable, but this results in a runtime exception as the parameter d resolves to bool even though the type of the generic is ulong, thereby binding the incorrect method:

class MyClass
{
    void Caller()
    {
        ulong val = 0;
        this.GetValue<ulong>(ref val);
    }

    void GetValue<T>(ref T val)
    {
        dynamic d = val; 
        GetValDynamic(ref d);
    }

    void GetValDynamic(ref dynamic val)
    {
        VendorLib v = new VendorLib();
        v.GetVal(ref val);
    }
}

Exception: Result Message: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : The best overloaded method match for 'VendorLib.GetVal(ref bool)' has some invalid arguments

The vendor library contains several GetVal overloads, of which GetVal(ref bool) is one and GetVal(ref ulong) another.

Why is the correct method not being bound?

Thanks!

If you don't want to check typeof(T) and call the respective method manually then reflection can work. Something like this...

  public class MyVendorLibWrapper
  {
    private readonly VendorLib vendorLib;

    public MyVendorLibWrapper()
    {
      this.vendorLib = new VendorLib();
    }

    public T GetValue<T>()
    {
      MethodInfo method = typeof(VendorLib)
        .GetMethod("GetVal", new Type[] { typeof(T).MakeByRefType() });

      object[] arguments = new object[] { default(T) };
      method.Invoke(this.vendorLib, arguments);
      return (T)arguments[0];
    }
  }

And called something like this...

MyVendorLibWrapper wrapper = new MyVendorLibWrapper();
int x = wrapper.GetValue<int>();

val is a dynamic , not a bool or a ulong . It is the wrong type. By using dynamic you are just cheating yourself out of the compile-time checking and just getting an error at runtime instead.

Looking at the way this code works the only purpose of generics and dynamic is to find a way to pass either a bool or a ulong to GetVal(...). From your code it looks like the only method that might need to be public is Caller(), in which case you can hide all this behind a common interface.

class MyClassULong : IMyClass
{
    void Caller()
    {
        ulong val = 0;
        this.GetValue(ref val);
    }

    void GetValue(ulong val)
    {
        VendorLib v = new VendorLib();
        v.GetVal(ref val);
    }

}

class MyClassBool : IMyClass
{
    void Caller()
    {
        bool val = false;
        this.GetValue(ref val);
    }

    void GetValue(bool val)
    {
        VendorLib v = new VendorLib();
        v.GetVal(ref val);
    }

}

public interface IMyClass
{
    void Caller();
}

Then any code invoking Caller() would be written against IMyClass, and therefore wouldn't care which implementation you used.

public void CallIt(IMyClass myClass)
{
    myClass.Caller();
}

There are lots of patterns to get round this type of problem. For a better understanding you really need to spend a good deal of time reading about OOP in C#, and spend time coding.

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