Създайте общ клас с вътрешен конструктор

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

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

Това предизвиква същата грешка по време на изпълнение.


person David Neale    schedule 06.09.2010    source източник
comment
Странно, не получавам никаква грешка с вашия код в .NET 4. Не сте сигурни дали това ограничение е отменено? Беше ли грешка по време на компилиране или по време на изпълнение?   -  person Paul Ruane    schedule 06.09.2010
comment
А, аз използвам .NET 3.5. Ще се поразровя. Това беше грешка по време на компилиране.   -  person David Neale    schedule 06.09.2010
comment
В този случай вижте отговора ми.   -  person Paul Ruane    schedule 06.09.2010


Отговори (3)


Можете да премахнете ограничението new() и да върнете:

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

въпреки че клиентът може да направи и това. Това обаче е предразположено към грешки по време на изпълнение.

Това е труден проблем за разрешаване по безопасен начин, тъй като езикът не позволява декларация на абстрактен конструктор.

person Ani    schedule 06.09.2010
comment
Опитах това - същата грешка просто се хвърля по време на изпълнение, вместо при компилиране. - person David Neale; 06.09.2010
comment
@David Neale: Извикването на претоварването nonPublic ще се справи с това. Актуализиран. - person Ani; 06.09.2010
comment
Отлично - не видях това претоварване. Благодаря. - person David Neale; 06.09.2010

Аргументът тип трябва да има публичен конструктор без параметри. Когато се използва заедно с други ограничения, ограничението new() трябва да бъде посочено последно.

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

редактиране: така че не, ако използвате ограничение 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();
        }
person Kikaimaru    schedule 06.09.2010

Може да има няколко заобиколни решения, както е показано по-долу, но не мисля, че искате да вървите по този начин!

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

  • Всяка конкретна реализация на FooBase ще се регистрира с FooFactory, предавайки фабричния метод, за да се създаде сама. Така че FooFactory ще използва вътрешния речник

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

person VinayC    schedule 06.09.2010