C # Могу ли я создать универсальный метод или свойство внутри неуниверсального класса, который возвращает другой универсальный класс? - PullRequest
3 голосов
/ 21 февраля 2011

У меня есть абстрактный обобщенный класс. Я хочу определить метод внутри, поэтому мне не придется делать это во всех производных классах.

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

Я выбираю хранилища через другой класс, который не является универсальным.

Как я могу позволить этому классу возвращать универсальный репозиторий на основе типа, который имеет универсальный вызывающий объект?

Я надеялся на что-то подобное.

public IRepository<T> Table<T>()
{
    return _container.Resolve<IRepository<T>>();
}

Если это будет свойство, будет еще лучше.

Ответы [ 2 ]

6 голосов
/ 21 февраля 2011

C # не может выразить тип "self", но вы можете эмулировать его с любопытным повторяющимся шаблоном (CRTP).

public class Base<TSelf> where TSelf : Base<TSelf> 
{
    // Make this a property if you want.
    public IRepository<TSelf> GetTable()
    {                   
        return _container.Resolve<IRepository<TSelf>>();          
    }
}

public class Derived : Base<Derived> {  }

Использование:

IRepository<Derived> table = new Derived().GetTable();  

Это не глупо. Для получения более подробной информации, прочитайте это сообщение в блоге Эрика Липперта: Curiouser и curiouser .


С другой стороны, если вам нужно, чтобы аргумент типа для вызова _container.Resolve основывался только на текущем типе, но мог возвращать более общий тип из метода, вам не нужно прибегать к этому шаблон. Вместо этого вы можете использовать отражение:

// If the container's Resolve method had an overload that 
// accepted a System.Type, it would be even easier.
public SomeBaseType GetTable()
{
   var repositoryType = typeof(IRepository<>).MakeGenericType(GetType());

   var result = _container.GetType()
                          .GetMethod("Resolve")
                          .MakeGenericMethod(repositoryType)
                          .Invoke(_container, null);

   return (SomeBaseType) result;     
}
1 голос
/ 21 февраля 2011

Я не вижу проблемы. Вы можете написать подобный код, который скомпилирован. Разве это не выполняет то, что вы хотите?

interface IRepository<T>
{
    T GetData();
}

class Container
{
    private object[] data = null;

    public T Resolve<T>()
    {
        return(T)data.First(t => t.GetType() is T);
    }
}

abstract class Handler<T>
{
    private Container _container;

    public IRepository<T> Table
    {
        get
        {
            return _container.Resolve<IRepository<T>>();
        }
    }
}
...