繁体   English   中英

带通用参数的接口与带通用方法的接口

[英]Interface with generic parameter vs Interface with generic methods

假设我有这样的界面和具体的实现

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 ++模板中很常见,您的示例将在该模板中编译,但是如果MyConcrete2任何用法如果不使用string调用My都将无法编译。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM