我有以下界面:
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.
}
}
任何人都可以帮助/解释它失败的原因吗?我的AggregateRoot
是一个班级......
答案 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);