45

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

public interface IMyInterface<T>
{
    T My();
}

public class MyConcrete : IMyInterface<string>
{
    public string My()
    {
        return string.Empty;
    }
}

所以我创建了 MyConcrete 实现strings,我可以有一个更具体的实现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>as的具体实现MyClass : MyInterface<string>并在这一点上停止泛型,为什么我不能用泛型方法来做到这一点 - T My<T>()

4

4 回答 4

43

您的通用方法实现也必须是通用的,因此它必须是:

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?
}
于 2013-07-11T14:34:21.610 回答
5

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

为了实现您想要的,您需要向接口提供 T 泛型参数,在您的第一个示例中:

public interface IMyInterface2<T>
{
        T My();
}

public class MyConcrete2 : IMyInterface2<string>
{
    public string My()
    {
        throw new NotImplementedException();
    }
}
于 2013-07-11T14:38:25.393 回答
3

当您编写通用方法时,定义用于保留占位符。当您调用该方法时,实际类型就会出现。所以你应该写

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

当您调用该方法时,您可以在那里使用字符串。

于 2013-07-11T14:39:09.020 回答
1

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

首先,接口是契约。当您实现时IMyInterface2,您保证您将实现一个名为的函数,该函数My采用泛型类型参数并返回该类型。 MyConcrete2不这样做。

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

于 2013-07-11T16:40:18.067 回答