Создать универсальный класс с внутренним конструктором - PullRequest
2 голосов
/ 06 сентября 2010

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

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>(); 

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

Ответы [ 4 ]

4 голосов
/ 06 сентября 2010

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

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

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

Эту проблему трудно решить безопасным способом, поскольку язык не допускает объявления абстрактного конструктора.

0 голосов
/ 02 марта 2011
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);
    }
}
0 голосов
/ 06 сентября 2010

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

  • Поместите оператор switch в Factory, который создаст экземпляр на основе типапараметра типа.

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

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

0 голосов
/ 06 сентября 2010

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

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

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

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();
        }
...