2009-12-06 88 views
0

我喜欢将我的定义与我的实现分开。我有一个接口实体:限制泛型在特定情况下失败

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

    bool ReadOnly { get; } 

    void FailIfReadOnly(); 

    E Copy(); 
} 

E是实际的实体类型,如Customer:

public interface Customer : Entity<Customer> 
{ 
} 

我的问题是FailIfReadOnly(执行):如果只读== true,则抛出一个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仅限于实体的子类。我的问题是,为什么我得到这个编译错误?这可能很简单。

+0

接口上“where E:Entity ”的用途是什么? – 2009-12-06 21:48:57

+1

这是一个递归定义是不是? IE类型限制是一个实体>? 这甚至可能吗? – Spence 2009-12-06 21:57:20

+0

@marcgravell - 通常这种递归类型限制的目的是在基类中实现可以返回派生类型的克隆或副本。 – x0n 2009-12-06 22:05:35

回答

4

首先,你的异常类不从异常派生:

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

然后注意到您的异常的构造函数不采取Entity<E>作为参数,而是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); 

非工作方法:尝试施放此到E:

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

这将编译,但在运行时失败,因为你的实施对象是不一样的类型作为参数E和不能投给它。

另一个小问题:您的if (!ReadOnly)检查是错误的。它应该是if (ReadOnly)

0

嗯......

错误消息是相当清楚的:你不能转换EntityImpl到E ...只是因为没有实体基于E的,也不执行转换操作符...

您可以使用马克的方式或重写实体接口作为抽象类与隐式运算符E(实体实体)和至少有一个参数E实例的构造函数。所以你所有派生类都可以做到这一点。