我希望能够做到这样的事情:
class A<T1, T2>
{
public void Call(T1 arg1, T2 arg2)
{
B b = new B();
b.DoSomething(arg1); // determine which overload to use based on T1
b.DoSomething(arg2); // and T2
}
}
class B
{
public void DoSomething(int x)
{
// ...
}
public void DoSomething(float x)
{
// ...
}
}
我知道可以使用if / else检查来完成,但这似乎并不优雅,特别是当我有20多种类型可供选择时。
答案 0 :(得分:8)
如果您想要类型安全,您可以做的最好的事情可能是:
class A<T1, T2>
{
public void Call<T>(T1 arg1, T2 arg2) where T : IDoSomething<T1>, IDoSomething<T2>, new()
{
T b = new T();
b.DoSomething(arg1);
b.DoSomething(arg2);
}
}
public interface IDoSomething<T>
{
void DoSomething(T arg);
}
public class B : IDoSomething<int>, IDoSomething<float>
{
void IDoSomething<int>.DoSomething(int arg)
{
Console.WriteLine("Got int {0}", arg);
}
void IDoSomething<float>.DoSomething(float arg)
{
Console.WriteLine("Got float {0}", arg);
}
}
你可以使用:
var a = new A<int, float>();
a.Call<B>(1, 4.0f);
答案 1 :(得分:4)
此方法不是类型安全的或可取的。
你可以将变量声明为dynamic
,这意味着它的类型将在运行时解析,而不是编译时。
public void Call(dynamic arg1, dynamic arg2)
{
B b = new B();
b.DoSomething(arg1); // determine which overload to use based on T1
b.DoSomething(arg2); // and T2
}
请注意,如果arg1
原来是一个字符串,并且没有适当的过载,那么您将获得RuntimeBinderException。
此外,由于您推迟了类型解析,因此性能略有下降。
答案 2 :(得分:0)
是的,他们很酷。
但是,它只适用于继承层次结构,因为在您的示例中:arg1必须是int,而arg2必须是float。您将收到编译器错误,因为类型声明T1,T2不限于float和int类型。
如果arg1是BaseA而arg2是BaseB,那么这个例子会更多。
然后你会像这样声明A类:
class A<T1, T2> where T1: BaseA, T2: BaseB
现在,对于任何T1继承自BaseA等的情况,它都可以。
当您使用A类时,运行时将知道实际使用的是什么类型,并选择正确的重载。
答案 3 :(得分:0)
您可以执行此操作,但仅在特定情况下,如果您可以对泛型使用where
约束,并且编译器知道会发生什么。
但是,除非您使用dynamic
,否则必须知道会发生什么。另请注意,where
泛型类型约束必须是类或接口。它不能(例如)int
。
简单的编译和运行的示例:
static void Main(string[] args)
{
A<C, D> test = new A<C, D>();
test.Call(new Cimpl(), new Dimpl());
}
class A<T1, T2> where T1 : C where T2 : D
{
public void Call(T1 arg1, T2 arg2)
{
B b = new B();
b.DoSomething(arg1); // determine which overload to use based on T1
b.DoSomething(arg2); // and T2
}
}
class Cimpl : C { }
class Dimpl : D { }
interface C
{ }
interface D
{ }
class B
{
public void DoSomething(C x)
{
// ...
}
public void DoSomething(D x)
{
// ...
}
}