具有泛型参数的接口与具有泛型方法的接口

本文关键字:接口 泛型方法 参数 泛型 | 更新日期: 2023-09-27 18:21:55

假设我有这样的接口和具体的实现

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>()来做到这一点?

具有泛型参数的接口与具有泛型方法的接口

您的泛型方法实现也必须是泛型的,因此它必须是:

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?
}

因为您的接口声明了一个通用方法T My<T>(),但您的实现没有实现具有该特定签名的函数。

为了实现您想要的,您需要向接口提供T通用参数,例如:

public interface IMyInterface2<T>
{
        T My();
}
public class MyConcrete2 : IMyInterface2<string>
{
    public string My()
    {
        throw new NotImplementedException();
    }
}

在编写泛型方法时,定义用于保留占位符。当您调用该方法时,实际类型会显示出来。所以你应该写

public T My<T>()
{
    throw new NotImplementedException();
}

当你调用这个方法时,你可以在那里使用字符串。

您的解决方案不起作用有两个原因。

首先,接口就是合同。当您实现IMyInterface2时,您保证将实现一个名为My的函数,该函数接受泛型类型参数并返回该类型。MyConcrete2不执行此操作。

其次,C#泛型不允许任何类型的参数专门化。(我确实希望C#支持这一点。)这在C++模板中是很常见的事情,您的示例将在模板中编译,但如果不使用string调用My,则MyConcrete2的任何用法都将无法编译。