0

I need to have certain attributes of my POCO entities updated on certain actions.

I defined the following Interfaces:

public interface IEntityPOCO
{
    Guid Id { get; set; }
}

public interface IHasLastChange : IEntityPOCO
{
    DateTime LastChange { get; set; }
}

Here's an example action method:

public void SomeStuff<T>(T entity) where T : class, IEntityPOCO
{
    entity.Id = Guid.NewGuid(); // Works like a charm.

    if (entity is IHasLastChange)
    {
        entity.LastChange = DateTime.Now; // Doesn't work. D'oh.
        (IHasLastChange)entity.LastChange = DateTime.Now; // Doesn't work either.
    }
}
  • Since there's quite a lot of different properties (all with corresponding Interfaces) that might be implemented by the POCO, going about the problem with different function signatures is pretty much out of question.
  • I'd rather not use reflection for performance reasons.

Is there any feasible way to put me out of my misery?

H H
  • 263,252
  • 30
  • 330
  • 514
vzwick
  • 11,008
  • 5
  • 43
  • 63

3 Answers3

4

You need more () in the casting:

 // (IHasLastChange)entity.LastChange = DateTime.Now;
   ((IHasLastChange)entity).LastChange = DateTime.Now; 

Since there's quite a lot of different properties

Then it will quickly pay to use a temp var:

if (entity is IHasLastChange)
{
    lastChange = (IHasLastChange) entity;
    lastChange.LastChange = DateTime.Now; 
    lastChange. ... 
}
H H
  • 263,252
  • 30
  • 330
  • 514
2

The common way to do this would be to cast the entity with as and check if it's null, like this:

var lastChangedEntity = entity as IHasLastChange;
if (lastChangedEntity != null)
{
    lastChangedEntity.LastChange = DateTime.Now;
}

But this leads to a nasty code smell as the number of different interfaces increase.

If this is the case, consider using the Strategy Pattern to handle it, in that way you will adhere to the Open/Closed Principle (OCP) and make your application more maintainable.

EDIT: A Strategy Pattern example would be:

public void SomeStuff<T>(T entity) where T : class, IEntityPOCO
{
    entity.Id = Guid.NewGuid(); // Works like a charm.

    // _processors is a List<IProcessEntities>
    var processors = _processors.Where(p => p.CanProcess(entity));

    foreach (var processor in processors)
    {
        processor.Process(entity);
    }
}

public interface IProcessEntities
{
    bool CanProcess<T>(T entity) where T : class, IEntityPOCO;

    void Process<T>(T entity) where T : class, IEntityPOCO;
}

public class LastChangedProcessor : IProcessEntities
{
    public bool CanProcess<T>(T entity) where T : class, IEntityPOCO
    {
        return typeof(IHasLastChange).IsAssignableFrom(typeof(T));
    }

    public void Process<T>(T entity) where T : class, IEntityPOCO
    {
        var lastChangeEntity = entity as IHasLastChange;
        if (lastChangeEntity != null) 
        {
            lastChangeEntity.LastChange = DateTime.Now;
        }
    }
}
khellang
  • 17,550
  • 6
  • 64
  • 84
1

You need to cast.

var hasLastChange = entity as IHasLastChange;
hasLastChange.LastChange = DateTime.Now; //It works!

Or

((IHasLastChange)entity).LastChange = DateTime.Now; //It also works!
Josh C.
  • 4,303
  • 5
  • 30
  • 51