2015-09-08 3 views
0

У меня есть следующий интерфейс:Как реализовать этот общий интерфейс для этого C# метод

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

Я пытался реализовать, но я получаю эту ошибку:

The constraints for type parameter 'TListing' of method 'Foo.Core.Models.AggregateRoot.Copy(TListing)' must match the constraints for type parameter 'T' of interface method 'FooCore.Interfaces.ICopyable.Copy(T)'. Consider using an explicit interface implementation instead.

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

enter image description here

Может ли кто-нибудь помочь/объяснить, почему это не удается? Мой AggregateRoot является классом ...

+0

вы пытались определить Т: класс при определении интерфейса вместо этого? –

+0

Я не знаю, что вы имеете в виду. Прости. –

+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 в отношении контравариантности входных данных.

Но даже если он был типа safe и не нарушил LSP, он все равно будет отклонен компилятором. C# требует, чтобы специализация класса и реализация интерфейса всегда выполнялись с точными, инвариантными сигнатурами и одинаковыми ограничениями. Это прописано в C# specification, в 13.4.3 Реализации универсальных методов:

When a generic method implicitly implements an interface method, the constraints given for each method type parameter must be equivalent in both declarations [...]

Но все-таки, 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); 
+0

Хм .. так что я должен определить его на уровне класса? почему это? –

+0

@ Pure.Krome Я просто понял, что мой первоначальный абзац сам по себе вводит в заблуждение. См. Мое редактирование. –

Смежные вопросы