假设我有这样的界面和具体实现
public interface IMyInterface<T>
{
T My();
}
public class MyConcrete : IMyInterface<string>
{
public string My()
{
return string.Empty;
}
}
所以我为strings
创建MyConcrete实现,我可以为int
创建一个更具体的实现。那没关系。但是,让我们说,我想做同样的事情,但是使用泛型方法,所以我有
public interface IMyInterface2
{
T My<T>();
}
public class MyConcrete2 : IMyInterface2
{
public string My<string>()
{
throw new NotImplementedException();
}
}
所以我有相同的IMyInterface2
,但它通过T My<T>()
定义了一般行为。在我的具体类中,我想实现My
行为,但对于具体的数据类型 - string
。但C#不允许我这样做。
我的问题是为什么我不能这样做?
换句话说,如果我可以创建MyInterface<T>
作为MyClass : MyInterface<string>
的具体实现并在此时停止泛化,为什么我不能用泛型方法 - T My<T>()
来做到这一点?
答案 0 :(得分:34)
您的通用方法实现也必须是通用的,因此它必须是:
public class MyConcrete2 : IMyInterface2
{
public T My<T>()
{
throw new NotImplementedException();
}
}
为什么你不能在这里做My<string>()
?因为接口契约需要一个方法,可以使用任何类型参数T
调用,并且您必须履行该合同。
为什么你不能在这一点上停止通用?因为它会导致以下情况:
类声明:
public interface IMyInterface2
{
T My<T>(t value);
}
public class MyClass21 : IMyInterface2
{
public string My<string>(string value) { return value; }
}
public class MyClass22 : IMyInterface2
{
public int My<int>(int value) { return value; }
}
用法:的
var item1 = new MyClass21();
var item2 = new MyClass22();
// they both implement IMyInterface2, so we can put them into list
var list = new List<IMyInterface2>();
list.Add(item1);
list.Add(item2);
// iterate the list and call My method
foreach(IMyInterface2 item in list)
{
// item is IMyInterface2, so we have My<T>() method. Choose T to be int and call with value 2:
item.My<int>(2);
// how would it work with item1, which has My<string> implemented?
}
答案 1 :(得分:3)
因为您的接口声明了泛型方法T My<T>()
,但您的实现没有实现具有该特定签名的函数。
要实现您的目标,您需要在第一个示例中为界面提供T generic参数:
public interface IMyInterface2<T>
{
T My();
}
public class MyConcrete2 : IMyInterface2<string>
{
public string My()
{
throw new NotImplementedException();
}
}
答案 2 :(得分:3)
当您编写通用方法时,定义用于保留占位符。调用方法时,实际类型会显示在图片中。所以你应该写
public T My<T>()
{
throw new NotImplementedException();
}
当你调用方法时,你可以在那里使用字符串。
答案 3 :(得分:1)
由于两个原因,您的解决方案无效。
首先,界面是合约。实现IMyInterface2
时,您保证将实现一个名为My
的函数,该函数接受泛型类型参数并返回该类型。 MyConcrete2
不会这样做。
其次,C#泛型不允许任何类型的参数专门化。 (我确实希望C#支持这个。)这是C ++模板中常见的事情,你的例子会编译,但MyConcrete2
的任何用法都不能编译,如果他们不用{My
调用{ {1}}。