C#泛型能这么酷吗?

C#泛型能这么酷吗?,c#,generics,overloading,C#,Generics,Overloading,我希望能够像这样: 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

我希望能够像这样:

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)
    {
       // ...
    }
}
A类
{
公共作废调用(T1 arg1、T2 arg2)
{
B=新的B();
b、 DoSomething(arg1);//根据T1确定要使用的重载
b、 DoSomething(arg2);//和T2
}
}   
B类
{
公共无效剂量测定(int x)
{
// ...
}
公共无效剂量测定(浮动x)
{
// ...
}
}

我知道可以通过if/else检查来完成,但这似乎不是很优雅,尤其是当我有20多种类型可供选择时。

这种方法既不安全也不可取

您可以将变量声明为,这意味着它的类型将在运行时解析,而不是在编译时解析

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
被证明是一个字符串,并且不存在适当的重载,您将得到一个字符串。
此外,性能也会受到轻微影响,因为您推迟了类型解析。

如果您想要类型安全,最好的办法可能是:

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);
    }
}
A类
{
公共void调用(T1 arg1,T2 arg2),其中T:IDoSomething,IDoSomething,new()
{
tb=新的T();
b、 剂量测定法(arg1);
b、 剂量测定法(arg2);
}
}
公共接口
{
无效剂量测定(T arg);
}
公共B类:我喜欢,我喜欢
{
void idoothing.DoSomething(int arg)
{
WriteLine(“Got int{0}”,arg);
}
无效。剂量(浮动参数)
{
WriteLine(“Got float{0}”,arg);
}
}
您可以像这样使用:

var a = new A<int, float>();
a.Call<B>(1, 4.0f);
var a=newa();
a、 呼叫(1,4.0f);

是的,它们很酷

但是,它只适用于继承层次结构,因为在您的示例中:arg1必须是int,arg2必须是float。您将收到一个编译器错误,因为您的类型声明T1、T2不限于float和int类型

如果arg1是BaseA,arg2是BaseB,那么该示例将提供更多信息

然后,您可以这样声明类A:

class A<T1, T2> where T1: BaseA, T2: BaseB
A类,其中T1:BaseA,T2:BaseB
现在,对于T1继承自BaseA等的任何情况,它都会起作用


当您使用类A时,运行时将知道实际使用的是什么类型,并选择正确的重载。

您可以这样做,但只有在特定情况下,如果您可以对泛型使用
where
约束,并且编译器知道要期望什么

但是,除非您使用的是
dynamic
,否则它必须知道会发生什么。还要注意,
其中
泛型类型约束必须是类或接口。它不能是(例如)一个
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)
    {
        // ...
    }
}
static void Main(字符串[]args)
{
A测试=新的A();
test.Call(new Cimpl(),new Dimpl());
}
A类,其中T1:C,其中T2:D
{
公共作废调用(T1 arg1、T2 arg2)
{
B=新的B();
b、 DoSomething(arg1);//根据T1确定要使用的重载
b、 DoSomething(arg2);//和T2
}
}
类Cimpl:C{}
类Dimpl:D{}
接口C
{ }
接口D
{ }
B类
{
公共无效剂量测定(C x)
{
// ...
}
公共空间剂量测定(D x)
{
// ...
}
}

你想解决什么问题?你真的试过了吗?我想你想要的是
动态的
,而不是泛型的我不能在我工作的环境中使用动态的,所以这不是一个选项。我认为这是对
动态的愚蠢使用,不一定能回答这个问题。问题是“C#泛型能这么酷吗?”这就排除了使用
dynamic
@MichaelJ.Gray实际上,许多关于堆栈溢出(,)的帖子都显示了
dynamic
关键字的这种用法。我不是说你应该使用它(我不会),我是说你可以用它来动态地确定应该调用哪个方法重载(这似乎是OP的问题,也是他的问题的核心)。@dcastro对于其他使用它的人来说,这并不意味着在这种情况下它是正确的。很多答案都暗示了一些糟糕的想法,这些想法打破了很多好的做法,甚至一点都不好笑。这个行业的一个悲哀的事实是:许多程序员在他们所做的事情上真的很糟糕。我不是说你是,但我想说清楚,别人这么做并不意味着你需要这么做。话虽如此,我接受你的回答,这就是答案。不多不少。我刚刚花了0.02美元解释说,我认为在Lee的建议上使用
dynamic
是愚蠢的。@MichaelJ.Gray我想你是对的。虽然我的目的只是简单地说明这个关键字的一种可能用法,但我想对一些读者来说,它可能会被认为是一种受鼓励的解决方案。我将编辑我的文章,使这一点更加明显。注意,这不适用于基本数据类型:。OP实际上可能使用类类型,但问题中的示例使用
int
float
+1实现类型安全,并描述实现所需功能的最严格的实现。