InvalidCastException при приведении сущности к интерфейсу для использования в статическом методе - PullRequest
0 голосов
/ 07 января 2012

У меня проблема с приведением сущности к интерфейсу для использования в статическом методе. Я получаю ошибку InvalidCastException . Мне нужно выполнить это приведение, потому что у меня есть статический метод, который должен принять определенное определение интерфейса. Я думаю (хотя я не пробовал), что использование абстрактного класса в отличие от интерфейса может сработать, но C # не поддерживает наследование от абстрактных классов, и моя сущность уже наследует от одного абстрактного класса.

Моя модель довольно проста. У меня есть один объект сущности - MemberStatus - который имеет Id, Name и DisplayOrder. Он наследуется от абстрактного класса Entity (который наследуется от IIdentifiableEntity) и реализует интерфейсы INamedEntity, IOrderedEntity. Каждый из этих абстрактных классов или интерфейсов содержит только одно свойство (Id, Name и DisplayOrder).

Вот мой код в проекте моего домена:

public abstract class Entity : IIdentifiableEntity
{
  public int Id { get; set; }
}

public interface INamedEntity
{
  string Name { get; set; } 
}

public interface IOrderedEntity
{
  float DisplayOrder { get; set; }
}

public class MemberStatus : Entity, INamedEntity, IOrderedEntity
{
  public string Name { get; set; }
  public float DisplayOrder { get; set; }
}

public interface IRepository<TEntity>
{
  TEntity FindById(int id);
  bool InsertOrUpdate(TEntity entity);
  //... More methods here
}

Вот мой статический метод (который я хочу использовать для любого IOrderedEntity):

public static void MoveDisplayOrder(IRepository<IOrderedEntity> repository, int id, bool moveUp)
{
  var currentStatus = repository.FindById(id);
  //...do reordering work
  repository.InsertOrUpdate(currentStatus);
}

В моем контроллере MVC (в моем веб-проекте) у меня есть следующее:

public class AdminController : Controller
{
  private readonly IRepository<MemberStatus> _memberStatusRepository;

  public AdminController(IRepository<MemberStatus> memberStatusRepository)
  {
    _memberStatusRepository = memberStatusRepository;
  }

  public ActionResult StatusMoveDisplayOrder(int id, bool moveUp)
  {
    // Code fails on the following line...
    MoveDisplayOrder((IRepository<IOrderedEntity>) _memberStatusRepository, id, moveUp);
    return RedirectToAction("Index");
  }

  // Rest of controller code here...
}

Код завершается ошибкой (во время выполнения ... он прекрасно компилируется), когда контроллер вызывает StatusMoveDisplayOrder, и он, в свою очередь, пытается вызвать статический MoveDisplayOrder. Весь этот код работал отлично, пока я не сделал MoveDisplayOrder статическим и не изменил первый параметр с IRepository<MemberStatus> на IRepository<IOrderedEntity>. Опять же, я сделал это изменение, чтобы можно было вызывать этот метод для любой сущности, которая имеет свойство DisplayOrder (реализует IOrderedEntity). Что я делаю не так?

К вашему сведению - я использую ninject, на случай, если там есть что-то, что мне нужно настроить.

1 Ответ

2 голосов
/ 07 января 2012

IRepository<MemberStatus> не является IRepository<IOrderedEntity>, хотя MemberStatus реализует IOrderedEntity.Вам нужно сделать IRepository ковариантным универсальным интерфейсом, подобным этому, если вы действительно хотите иметь возможность выполнять преобразование типов.

interface IRepository<out T>
{
}

http://msdn.microsoft.com/en-us/library/dd997386.aspx

Это невозможно, как написанопотому что методы IRepository не смогут принять TEntity в качестве параметра.Вместо приведения вы можете изменить статический метод ..

public static void MoveDisplayOrder<T>(IRepository<T> repository, int id, 
    bool moveUp) where T : IOrderedEntity
{
  var currentStatus = repository.FindById(id);
  //...do reordering work
  repository.InsertOrUpdate(currentStatus);
}
...