在我正确理解C#的过程中,我发现自己在询问在泛型方法参数上指定接口约束与简单地将接口指定为参数类型之间的实际区别是什么?
public interface IFoo
{
void Bar();
}
public static class Class1
{
public static void Test1<T> (T arg1) where T : IFoo
{
arg1.Bar();
}
public static void Test2(IFoo arg1)
{
arg1.Bar();
}
}
修改
我知道我的例子非常狭窄,因为它只是一个例子。我对超出其范围的差异非常感兴趣。
答案 0 :(得分:12)
在您的具体示例中没有区别。但采取以下方法:
public static class Class1
{
public static T Test1<T>(T arg1) where T : IFoo
{
arg1.Bar();
return arg1;
}
public static IFoo Test2(IFoo arg1)
{
arg1.Bar();
return arg1;
}
}
Test1
将返回特定类型的arg1,而Test2
将仅返回该接口。这通常用在流畅的界面中。
扩展示例:
public interface IFoo
{
void Bar();
}
public class Foo : IFoo
{
// implementation of interface method
public void Bar()
{
}
// not contained in interface
public void FooBar()
{
}
}
var foo = new Foo();
Class1.Test1(foo).FooBar(); // <- valid
Class1.Test2(foo).FooBar(); // <- invalid
答案 1 :(得分:6)
您给出的示例没有任何区别。另一方面,使用通用版本可以在将来扩展约束列表(where T : IFoo, IOther
),而无需更改方法签名。
答案 2 :(得分:4)
我只想强调别人给出的答案。
Test(IFoo foo)
和Test<T>(T foo) where T : IFoo
之间存在差异。有一个真正的区别,就像List<object>
(或者说,ArrayList
,它会收到object
)和List<string>
之间存在巨大差异。
Test (IFoo foo)
,为您提供多态性和类型继承的好处,就像List<object>
一样。它允许您构建一个处理所有IFoo
类型的类。但有时候我不只是想要多态,我想要一个只能保存字符串的列表 - List<string>
给了我这一点,而不需要我在ArrayList
上写一个强类型的包装器。
您的代码相同。假设我有class Comparer<T> where T:IFoo
。我希望能够使用此类将Foo1
个对象相互比较,或者将Foo2
相互比较,但我不希望能够将Foo1
与Foo2
进行比较public class Comparer
{
public bool Compare1<T>(T first, T second) where T : IFoo {...}
public bool Compare2 (IFoo first, IFoo second) {...}
}
Foo1 first = new Foo1();
Foo2 second = new Foo2();
myComparer.Compare1(first, second); // won't compile!
myComparer.Compare2(first, second); // Compiles and runs.
。强类型泛型方法将强制执行,而多态的方法则不会:
{{1}}
答案 3 :(得分:0)
这完全是类型铸造的问题。如果你的方法必须返回T,那么Test1将不需要转换,并且由于Test2只返回一个接口,你需要使用显式或隐式类型转换来获得最终类型。
答案 4 :(得分:0)
接口约束通常与例如IFoo, new()
...允许您完全操作对象T
,创建,初始化集合等 - 并按照建议返回T.虽然只是界面,你不知道它是哪个类(T)。