Создать универсальный класс с внутренним конструктором

StackOverflow https://stackoverflow.com/questions/3650707

Вопрос

Можно ли построить объект со своим внутренним конструктором в пределах универсального метода?

public abstract class FooBase { }

public class Foo : FooBase {
   internal Foo() { }
}

public static class FooFactory {
    public static TFooResult CreateFoo<TFooResult>()
    where TFooResult : FooBase, new() {
        return new TFooResult();
    }
}

FooFactory проживает в той же сборке, что и Foo. Отказ Классы называют заводским методом, как это:

var foo = FooFactory.CreateFoo<Foo>();

Они получают ошибку времени компиляции:

«Foo» должен быть не абстрактным типом с общедоступным параметральным конструктором, чтобы использовать его в качестве параметра «Tfootype» в универсальном типе или методе «foofactory.createfoo ()

Есть ли способ обойти это?

Я также пробовал:

Activator.CreateInstance<TFooResult>(); 

Это поднимает ту же ошибку во время выполнения.

Это было полезно?

Решение

Вы могли бы удалить new() Ограничение и возврат:

//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true); 

Хотя клиент мог это сделать тоже. Это, однако, склонна к ошибкам времени выполнения.

Это сложная проблема, чтобы решить безопасную манера, так как язык не разрешает абстрактный конструктор.

Другие советы

Аргумент типа должен иметь публичный Конструктор без параметров. При использовании вместе с другими ограничениями, новое () ограничение должно быть указано последним.

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

Редактировать: Так что нет, если вы используете новый () ограничения, вы не можете пройти этот класс, если вы не используете новый () ограничения, вы можете попробовать использовать отражение для создания нового экземпляра

public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
        {
            return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
            //return new TFooResult();
        }

Там может быть мало работы, как показано ниже, но я не думаю, что вы хотите пойти так!

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

  • Каждое бетонное внедрение FOOBASE будет регистрироваться с кофефактором, проходящими заводским методом для создания его самостоятельно. Так что кофефактория будет использовать внутренний словарь

  • Расширение на аналогичной строке, кроме отображения между параметрами типа и бетонной реализацией, будет внешний код (XML-файл, конфигурация и т. Д.). IOC / DI контейнеры также могут помочь здесь.

public class GenericFactory
{
    public static T Create<T>(object[] args)
    {
        var types = new Type[args.Length];
        for (var i = 0; i < args.Length; i++)
            types[i] = args[i].GetType();

        return (T)typeof(T).GetConstructor(types).Invoke(args);
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top