C#:从泛型调用外部程序集中的重载方法
C#: Call overloaded method in external assembly from generic
我有一个引用包含多个重载实例方法的第 3 方 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)
是一个,GetVal(ref ulong)
是另一个。
为什么没有绑定正确的方法?
谢谢!
val
是 dynamic
,而不是 bool
或 ulong
。这是错误的类型。通过使用 dynamic
,您只是在欺骗自己,让自己脱离编译时检查,而只是在运行时遇到错误。
查看此代码的工作方式,泛型和动态的唯一目的是找到一种将 bool 或 ulong 传递给 GetVal(...) 的方法。从您的代码看来,唯一可能需要 public 的方法是 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,并花时间编码。
如果您不想检查 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>();
我有一个引用包含多个重载实例方法的第 3 方 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)
是一个,GetVal(ref ulong)
是另一个。
为什么没有绑定正确的方法?
谢谢!
val
是 dynamic
,而不是 bool
或 ulong
。这是错误的类型。通过使用 dynamic
,您只是在欺骗自己,让自己脱离编译时检查,而只是在运行时遇到错误。
查看此代码的工作方式,泛型和动态的唯一目的是找到一种将 bool 或 ulong 传递给 GetVal(...) 的方法。从您的代码看来,唯一可能需要 public 的方法是 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,并花时间编码。
如果您不想检查 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>();