общие свойства абстрактного класса c # - PullRequest
2 голосов
/ 10 января 2012

Рассмотрим следующий код:

public abstract class RepositoryBase<T> where T : class
{
    #region Members

    private MyContext dataContext;
    private readonly IDbSet<T> dbset;

    #endregion

    protected RepositoryBase(IDatabaseFactory databaseFactory)
    {
        DatabaseFactory = databaseFactory;
        dbset = DataContext.Set<T>();
    }

    protected IDatabaseFactory DatabaseFactory
    {
        get; private set;
    }

    protected MyContext DataContext
    {
        get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
    }

    public virtual void Delete(T entity)
    {
        dbset.Remove(entity);
    }

Я бы хотел заменить метод Delete на приведенный ниже, поскольку я бы предпочел просто установить для поля Deleted значение true в моем объекте, чтобы указать, что он удален, вместо того, чтобы действительно его удалять.

    public virtual void Delete(T entity)
    {
        entity.Deleted = true;
        dbset.Attach(entity);
        dataContext.Entry(entity).State = EntityState.Modified;
    }

Я использую объекты POCO, и свойство Deleted существует во всех из них. Однако в приведенном выше коде сущность имеет тип T, и T «не знает», что существует свойство Deleted во всех объектах, которые оно может представлять. Какой самый элегантный способ решить эту проблему?

Кстати, я хотел бы получить доступ к другим полям (DateCreated, CreatedBy, DateModified и ModifiedBy) аналогичным образом в моем абстрактном классе.

ОБНОВЛЕНИЕ : Я попробовал как интерфейс, так и решение класса Abstract, что сначала казалось хорошим, но затем я получил следующее сообщение об ошибке в обоих случаях при компиляции:

Ошибка 11 Тип «MyProject.Domain.Person» нельзя использовать в качестве параметра типа «T» в универсальном типе или методе «MyProject.Data.Infrastructure.RepositoryBase». Не существует неявного преобразования ссылок из MyProject.Domain.Person в MyProject.Domain.AbstractEntity.

А вот код, на который ссылается сообщение об ошибке:

namespace MyProject.Data
{ 
    public class PersonRepository : RepositoryBase<Person>, IPersonRepository
    {
        public PersonRepository(IDatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }
    }

    public interface IPersonRepository : IRepository<Person>
    {

    }
}

Обновление 2:

Я наконец-то заставил его работать с решением, предложенным SLaks. Я использовал интерфейс и изменил шаблон, генерирующий все объекты POCO, чтобы они все были получены из следующего интерфейса IEntity:

namespace MyProject.Domain
{
    public interface IEntity
    {
        System.DateTime CreatedDate
        {
            get;
            set;
        }

        string CreatedBy
        {
            get;
            set;
        }

        System.DateTime ModifiedDate
        {
            get;
            set;
        }

        string ModifiedBy
        {
            get;
            set;
        }

        bool Deleted
        {
            get;
            set;
        }
    }
}

Использование абстрактного класса сущностей было бы более сложным, поскольку тогда все свойства в абстрактном классе пришлось бы переопределять в классах сущностей.

Ответы [ 4 ]

5 голосов
/ 10 января 2012

Поместите ваше свойство Deleted в интерфейс (скажем, IDeleteable) и ограничьте класс общим ограничением:

public interface IDeleteable { Boolean Deleted { get; set; } }

public abstract class RepositoryBase<T> where T : class, IDeleteable

РЕДАКТИРОВАТЬ: Я думал, что это подразумевается, но вам нужно реализовать интерфейс в ваших классах сущностей, например,

public class Person : IDeleteable { ... }
3 голосов
/ 10 января 2012

Вы можете использовать абстрактный класс для ограничения

// from
public abstract class RepositoryBase<T> where T : class

// to
public abstract class RepositoryBase<T> where T : AbstractEntity

Где AbstractEntity будет иметь все необходимые вам свойства.Абстрактный класс в отличие от интерфейса позволит вам обеспечить некоторую реализацию по умолчанию.

3 голосов
/ 10 января 2012

Вы должны создать интерфейс с Deleted и другими свойствами и реализовать его в ваших классах сущностей.
Затем вы можете ограничить параметр универсального типа для реализации интерфейса.

1 голос
/ 10 января 2012

Другие упоминали об использовании интерфейса или абстрактного класса. Это то, что я всем сердцем рекомендую. Если по какой-то глупой причине это невозможно, вы также можете использовать рефлексию:

entity.Deleted = true;

будет заменено на:

var type = typeof(T);
var property = type.GetProperty("Deleted");
property.SetValue(entity, true, null);
...