C#:从通用

时间:2015-05-20 23:05:08

标签: c# generics dynamic

我有一个项目引用包含多个重载实例方法的第三方c#程序集。我想通过代码中的泛型调用其中一个方法,调用参数类型与泛型类型匹配的实例方法:

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'

我最接近的是通过使用动态变量,但是这会导致运行时异常,因为参数d解析为bool,即使泛型的类型是ulong,从而绑定了不正确的方法:

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);
    }
}

例外: 结果消息:Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:'VendorLib.GetVal(ref bool)'的最佳重载方法匹配具有一些无效参数

供应商库包含多个GetVal重载,其中GetVal(ref bool)为1,GetVal(ref ulong)为另一个。

为什么没有绑定正确的方法?

谢谢!

2 个答案:

答案 0 :(得分:2)

如果您不想检查typeof(T)并手动调用相应的方法,则反射可以起作用。像这样......

  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];
    }
  }

并称之为......

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

答案 1 :(得分:1)

valdynamic,而不是boolulong。这是错误的类型。通过使用dynamic,您只是在编译时检查中欺骗自己,而只是在运行时收到错误。

查看此代码的工作方式泛型和动态的唯一目的是找到一种方法将bool或ulong传递给GetVal(...)。从您的代码看起来,可能需要公开的唯一方法是Caller(),在这种情况下,您可以将所有这些隐藏在公共接口后面。

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();
}

然后,任何调用Caller()的代码都将针对IMyClass编写,因此不关心您使用的实现。

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

有很多模式可以解决这类问题。为了更好地理解,你真的需要花大量时间阅读C#中的OOP,并花时间编写代码。