限制泛型类型在特定情况下失败

时间:2009-12-06 21:44:29

标签: c# generics constraints

我喜欢将我的定义与我的实现分开。我有一个接口实体:

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()的实现:如果ReadOnly == 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);导致编译错误:

  

'EntityIsReadOnlyException.EntityIsReadOnlyException(E)'的最佳重载方法匹配有一些无效的参数

     

参数'1':无法从'EntityImpl'转换为'E'

我能做到:

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

甚至:

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

但不是:

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

在这两种情况下,E仅限于实体的子类。我的问题是,为什么我会收到此编译错误?这可能非常简单。

2 个答案:

答案 0 :(得分:4)

首先,您的异常类不是从Exception派生的:

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)

答案 1 :(得分:0)

嗯......

错误信息非常明确:您无法将EntityImpl转换为E ...只是因为实体不是从E派生而且还没有实现转换运算符......

您可以使用Mark的方式或将Entity接口重写为具有隐式运算符E(实体实体)的抽象类和具有至少一个参数E实例的构造函数。所以你派生的所有类都能够实现这一点。

相关问题