Общие типы и интерфейсы - PullRequest
0 голосов
/ 18 ноября 2018

Я пытаюсь абстрагировать свой простой IRepository параметр сущности с абстрактным типом Entity<T>, чтобы подчиняться принципу СУХОЙ и не повторять Create(this) в дочерних классах. Но я сталкиваюсь с этой ошибкой:

CS1503 Аргумент 1: невозможно преобразовать из «Entity» в «T»

IRepository.cs:

public interface IRepository<T>
{
    void Create(T entity);
    IEnumerable<T> ReadAll();
}

Entity.cs:

public abstract class Entity<T>
{
    protected IRepository<T> repository;

    public void Create()
    {
        repository.Create(this);//Error occurs here on this
    }
}

Но если сделать public void Create() абстрактным и реализовать в подклассе, все пойдет нормально:

Entity.cs

public abstract class Entity<T>
{
    protected IRepository<T> repository;

    public abstract void Create();//Signature changed
}

TestEntity.cs

public class TestEntity:Entity<TestEntity>
{
    public override void Create()
    {
        repository.Create(this);
    }
}

Но, очевидно, этот метод будет скопирован и вставлен во все подклассы Entity.

Для дополнительной помощи моим дорогим друзьям:

public abstract class Base<T>
{
    public abstract String GetName();
    public String GetMyName()
    {
        return $"My Name is :{this.GetName()} Type:{this.GetType().ToString()} Is Base<T>:{this is Base<T>}";
    }
}

public class Sample : Base<Sample>
{
    public override string GetName()
    {
        return nameof(Sample);
    }
}

и MessageBox.Show(new Sample().GetMyName()); результат будет:

Меня зовут: Тип выборки: Пример базы: True

без ошибок.

Это еще один ответ, основанный на ответе одного из друзей:

public interface IRepository<T>
{
    void Create(Entity<T> entity);
    IEnumerable<T> ReadAll();
}

public abstract class Entity<T>
{
    protected IRepository<T> repository;

    public virtual void Create()
    {
        repository.Create(this);
    }
}

public class TestEntity : Entity<TestEntity>
{
    public String Name { get; set; }
}

public class Repository<T> : IRepository<T>
{
    List<T> list = new List<T>();
    public void Create(Entity<T> entity)
    {
        list.Add(this);//Error
        list.Add(entity);//Also Error
    }

    public IEnumerable<T> ReadAll()
    {
        return list;
    }
}

Ответы [ 5 ]

0 голосов
/ 19 ноября 2018

Create(this) метод сахара возможен, вот как я делаю вывод на

    public interface IEntity
    {
    }

    public interface IEntity<T> : IEntity 
           where T : IEntity
    {
    }

    public class BaseEntity<T> : IEntity 
           where T : IEntity, IEntity<T> 
    {
    }

    public interface IRepository<T> 
           where T: IEntity
    {
        void Create(T entity);
        IEnumerable<T> ReadAll();
    }

    public class Entity<T> : BaseEntity<T> 
          where T: IEntity, 
                   IEntity<T>, 
                   IEquatable<Entity<T>>        
    {
        protected IRepository<IEntity> repository;

        public virtual void Create()
        {
            repository.Create(this);
        }

        public bool Equals(Entity<T> other)
        {
            throw new NotImplementedException();
        }
    }

Это определенно добавляет больше сложности, так что лучше реорганизовать Create (this).

0 голосов
/ 18 ноября 2018

Может быть, вы должны использовать Entity<T> в своих методах интерфейса вместо <T>:

public interface IRepository<T>
{
    void Create(Entity<T> entity);
    IEnumerable<Entity<T>> ReadAll();
}

public abstract class Entity<T>
{
    protected IRepository<T> repository;

    public void Create()
    {
        repository.Create(this);
    }

    public IEnumerable<Entity<T>> ReadAll()
    {
        return repository.ReadAll();
    }
}
0 голосов
/ 18 ноября 2018

Вам нужно изменить void Create(T entity); на void Create(Entity<T> entity); в вашем IRepository<T> интерфейсе, чтобы эта работа работала.

public interface IRepository<T>
{
    void Create(Entity<T> entity);
    IEnumerable<T> ReadAll();
}

public abstract class Entity<T>
{
    public T Value;
    protected IRepository<T> repository;

    public void Create()
    {
        repository.Create(this);
    }
}

public class TestEntity : Entity<TestEntity>
{
}

public class Repository<T> : IRepository<T>
{
    List<T> list = new List<T>();
    public void Create(Entity<T> entity)
    {
        list.Add(entity.Value);
    }

    public IEnumerable<T> ReadAll()
    {
        return list;
    }
}
0 голосов
/ 18 ноября 2018

Проблема

Ваша проблема связана с тем, что ваш IRepository класс ожидает тип T, но вы передаете его Entity<T> вместо T.

Если бы вы использовали этот класс со значением T, являющимся строкой, вы бы получили следующее:

public interface IRepository<string>
{
    void Create(string entity);
    IEnumerable<string> ReadAll();
}

public abstract class Entity<string>
{
    protected IRepository<string> repository;

    public abstract void Create();//Signature changed
}

public abstract class Entity<string>
{
    protected IRepository<string> repository;

    public void Create()
    {
        //Here the compiler is expecting the parameter to be of type string, 
        //but you are passing a Entity<string> instead.
        //The compiler doesn't know how to cast it, so it throws an error.
        repository.Create(this);
    }
}

Решения

Как говорят другие решения,вы можете сделать так, чтобы ваш полевой репозиторий принимал Entity<T> вместо T, что решило бы это и действительно принесло бы больше сложности.

Другое решение состоит в том, чтобы изменить метод «Create» вашего интерфейса следующим образом:

public interface IRepository<T>
{
    void Create(Entity<T> entity);
    IEnumerable<T> ReadAll();
}

Но это заставит ваш интерфейс работать только с классами Entities.

0 голосов
/ 18 ноября 2018

Проблема в том, что ваша декларация класса Entity, попробуйте следующее:

public abstract class Entity<T>
    {
        protected IRepository<Entity<T>> repository;

        public void Create()
        {
            repository.Create(this);
        }
    }
...