views:

83

answers:

3

I like to separate my definitions from my implementations. I have an interface Entity:

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

    bool ReadOnly { get; }

    void FailIfReadOnly();

    E Copy();
}

E is the actual entity type, such as Customer:

public interface Customer : Entity<Customer>
{
}

The problem I have is the implementation of FailIfReadOnly(): if ReadOnly == true, then throw an 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);
    }
}

The throw new EntityIsReadOnlyException<E>(this); causes a compilation error:

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

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

I can do:

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

and even:

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

but not:

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

In both cases, E is restricted to subclasses of Entity. My question is, why do I get this compilation error? It's probably something very simple.

+4  A: 

Firstly, your exception class doesn't derive from Exception:

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

Then notice that your exception's constructor doesn't take an Entity<E> as a parameter, but an E.

Method 1: Change your constructor to take an Entity<E>:

public EntityIsReadOnlyException(Entity<E> entity)

Method 2: Pass other to your exception:

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

...

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

Non working method: Try to cast this to an E:

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

This compiles, but fails at runtime because your implementation object isn't the same type as the parameter E and cannot be cast to it.

Another minor point: your if (!ReadOnly) check is the wrong way around. It should be if (ReadOnly).

Mark Byers
A: 

Well...

Error message is pretty clear: you can't convert EntityImpl to E... Just because Entity not derived from E nor implemented casting operators...

You can use Mark's way or rewrite Entity interface as abstract class with implicit operator E(Entity entity) and constructor with at least one parameter E instance. So all you derived classes will be able to to this.

Trickster
A: 

@Mark Byers

Thank you, that works.

Firstly, your exception class doesn't derive from Exception: Another minor point: your if (!ReadOnly) check is the wrong way around. It should be if (ReadOnly).

That too.

Just for my understanding: E refers to the correct type in EntityImpl, but not in EntityIsReadOnlyException. Why do I need to make the constructor parameter type to Entity<E>, but in EntityImpl I don't?

Jeroen