Проблемы с абстрактными типами и интерфейсами в качестве параметров универсального типа с ограничением new () - PullRequest
2 голосов
/ 06 января 2010

Мне нужно иметь параметр универсального типа в качестве интерфейса, однако я хотел бы создать экземпляр типа в универсальном классе (SomeGenericType) следующим образом:

class Program
{
    static void Main(string[] args)
    {
        var val = new SomeGenericType<ISomeInterface>();

        Console.ReadKey();
    }
}

internal class SomeGenericType<T> where T : new()
{
    public SomeGenericType()
    {
        var test = new T();  
    }
}

public class SomeClass : ISomeInterface
{
    public string TestVal { get; set; }
}

public interface ISomeInterface
{
    string TestVal { get; set; }
}

Это приводит к следующей ошибке времени компиляции:

"ISomeInterface должен быть неабстрактного типа с открытым конструктором без параметров, чтобы использовать его в качестве параметра 'T' в универсальном типе или методе SomeGenericType"

Я понимаю, почему это происходит, однако мне было интересно, есть ли способ обойти эту проблему?

Спасибо.

Ответы [ 4 ]

6 голосов
/ 06 января 2010

Нет, ограничение new() требует, чтобы экземпляр типа мог быть создан с синтаксисом

new T()

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

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

Activator.CreateInstance<T>()

вместо того, чтобы создать объект. Тогда, пока фактический тип, используемый во время выполнения, удовлетворяет этим ограничениям, ваш код будет работать так, как вы хотите. Однако, если вы попытаетесь использовать интерфейс или абстрактный класс, вы столкнетесь с ошибкой во время выполнения.

В вашем конкретном случае эта строка выдаст исключение

var val = Activator.CreateInstance<SomeGenericType<ISomeInterface>>();

Вы прошли ошибку времени компиляции, но безрезультатно.

2 голосов
/ 06 января 2010

Альтернативная идея, которая может быть неактуальной, но похоже, что вы ищете способ запросить ISomeInterface и получить экземпляр его реализации по умолчанию SomeClass. Это тот тип вещей, который контейнер Inversion of Control (IOC) может обработать для вас. Если вы хотите продолжить исследование, вы можете взглянуть на Spring.NET, Microsoft Unity, AutoFac, LinFu или одну из многих других платформ.

1 голос
/ 07 января 2010

Проблема в том, что у компилятора нет возможности узнать, какой класс создать для данного интерфейса. Как указывает Дэвид М:

Это та вещь, которую контейнер Inversion of Control (IOC) может обработать для вас

Я думаю, что использование фреймворка может быть слишком сложным для этого простого требования. Что вы можете сделать, это создать собственный класс Factory, например:

public class Factory
{
  Dictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();

  public void Register<IType, CType>()
  {
    typeMapping.Add(typeof(IType),typeof(CType));
  }

  public IType Create<IType>()
  {
    Activator.CreateInstance(typeMapping[typeof(IType)]);
  }
}

добавьте несколько проверок работоспособности, и этот класс должен быть готов к использованию.

1 голос
/ 06 января 2010

Проблема здесь в том, что ограничение new связано с реализацией конкретного типа. Это никогда не может работать просто с интерфейсом или абстрактным классом, так как они не могут быть напрямую созданы. Вы должны предоставить конкретный класс здесь

var val = new SomeGenericType<SomeClass>()
...