Reputation: 1
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.
Upvotes: 0
Views: 130
Reputation: 837916
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)
.
Upvotes: 4
Reputation: 2524
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.
Upvotes: 0