如何为此C#方法实现此通用接口

时间:2015-09-08 13:27:00

标签: c# .net generics

我有以下界面:

public interface ICopyable
{
    void Copy<T>(T source) where T : class;
}

我试图实现它,但我不断收到此错误:

  

方法'Foo.Core.Models.AggregateRoot.Copy(TListing)'的类型参数'TListing'的约束必须匹配接口方法'FooCore.Interfaces.ICopyable.Copy(T)的类型参数'T'的约束)”。请考虑使用显式接口实现。

public abstract class AggregateRoot : ICopyable
{
    public virtual void Copy<TListing>(TListing newAggregateRoot) 
        where TListing : AggregateRoot
    {
       // my code here.
    }
}

enter image description here

任何人都可以帮助/解释它失败的原因吗?我的AggregateRoot是一个班级......

1 个答案:

答案 0 :(得分:5)

假设您的代码已编译完毕。然后你可以这样做:

class Derived : AggregateRoot
{
}

然后:

var derived = new Derived();
ICopyable copyable = derived;
copyable.Copy<string>("Hello!");

这没关系,因为ICopyable.Copy<T>需要一个类的类型参数 - 而string是一个类。但是必须将它调度到实际需要T : AggregateRoot的方法。这必须在运行时失败 - 所以编译器只是事先拒绝它。

更一般地说,问题在于您尝试使用比接口所说的更严格的实现来实现特定接口。这不是类型安全的 - 并且在输入的逆转方面会违反Liskov Substitution Principle

但即使 类型安全并且它没有违反LSP,它仍然会被编译器拒绝。 C#要求专门化一个类并实现一个接口总是使用精确的,不变的签名和相同的约束来完成。这是在C# specification 13.4.3泛型方法的实现中详细说明的:

  

当泛型方法隐式实现接口方法时,为每个方法类型参数指定的约束在两个声明中都必须相同[...]

但是,C#允许通用接口(相同泛型类型定义)之间的隐式转换的差异。因此,如果将代码更改为以下内容,则代码将起作用:

public interface ICopyable<in T>
    where T : class
{
    void Copy(T source);
}

public abstract class AggregateRoot : ICopyable<AggregateRoot>
{
    public virtual void Copy(AggregateRoot newAggregateRoot) 
    {
       // my code here.
    }
}

现在你可以执行以下操作,编译并且类型安全:

var derived = new Derived();
ICopyable<AggregateRoot> aggregateCopyable = derived;
ICopyable<Derived> derivedCopyable = aggregateCopyable;
derivedCopyable.Copy(derived);