2009-12-06 5 views
0

Мне нравится отделять свои определения от моих реализаций. У меня есть интерфейс Entity:Ограничение типа общего типа не выполняется в конкретной ситуации

public interface Entity<E> where E : Entity<E> 
{ 
    EntityId EntityId { get; } 

    bool ReadOnly { get; } 

    void FailIfReadOnly(); 

    E Copy(); 
} 

E является фактическим тип объекта, например, Заказчик:

public interface Customer : Entity<Customer> 
{ 
} 

У меня проблема является реализация FailIfReadOnly(): если ReadOnly == верно, то бросить EntityIsReadOnlyException.

public class EntityIsReadOnlyException<E> where E : Entity<E> 
{ 
    public EntityIsReadOnlyException(E entity) 
     : base(string.Format("Entity {0} is read only", entity.EntityId)) 
    { 
    } 
} 

public class EntityImpl<E> : Entity<E> where E : Entity<E> 
{ 
    public EntityImpl(E other) 
    { 
    } 

    public bool ReadOnly 
    { 
     get; 
     protected set; 
    } 

    public void FailIfReadOnly() 
    { 
     if (! ReadOnly) throw new EntityIsReadOnlyException<E>(this); 
    } 
} 

throw new EntityIsReadOnlyException<E>(this); вызывает ошибку компиляции:

The best overloaded method match for 'EntityIsReadOnlyException.EntityIsReadOnlyException(E)' has some invalid arguments

Argument '1': cannot convert from 'EntityImpl' to 'E'

я могу сделать:

EntityIsReadOnlyExcetion<Customer> exc = new EntityIsReadOnlyException<Customer>(customerImpl); 

и даже:

Entity<E> entity = new EntityImpl<E>(this); 

но не:

EntityIsReadOnlyException<E> exc = new EntityIsReadOnlyException<E>(this); 

В обоих случаях E ограничивается подклассами Entity. Мой вопрос: почему я получаю эту ошибку компиляции? Это, наверное, что-то очень простое.

+0

Какова цель 'where E: Entity ' на интерфейсе? –

+1

Это рекурсивное определение, не так ли? IE ограничение типа - это объект >? Возможно ли это? – Spence

+0

@marcgravell - обычно целью таких рекурсивных ограничений типа является реализация клона или копии в базовом классе, который может возвращать производный тип. – x0n

ответ

4

Во-первых, ваш класс исключения не вытекает из исключений:

public class EntityIsReadOnlyException<E> : Exception where E : Entity<E> 

Затем обратите внимание, что конструктор ваше исключение в не принимает Entity<E> в качестве параметра, но Е.

Метод 1: Измените конструктор, чтобы принять Entity<E>:

public EntityIsReadOnlyException(Entity<E> entity) 

Метод 2: Передайте other вашему исключение:

E other; 
public EntityImpl(E other) 
{ 
    this.other = other; 
} 

... 

if (ReadOnly) throw new EntityIsReadOnlyException<E>(other); 

Non метод работы: Попробуйте закинуть на E:

if (ReadOnly) throw new EntityIsReadOnlyException<E>((E)(Entity<E>)other); 

компилируется, но терпит неудачу во время выполнения, потому что ваш объект реализации не совпадает с типом параметра Е и не может быть бросить на него.

Еще одна небольшая точка: ваш if (!ReadOnly) проверка неправильного пути. Он должен быть if (ReadOnly).

0

Ну ...

Сообщение об ошибке довольно ясно: вы не можете преобразовать EntityImpl Е ... Просто потому, что сущность не является производным от Е, ни реализованы операторы литья ...

Вы можете использовать Mark или переписать интерфейс Entity как абстрактный класс с неявным оператором E (Entity entity) и конструктором с хотя бы одним экземпляром параметра E. Таким образом, все, что вы получили классы, смогут это сделать.

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