Program Club

대리자로 생성자-C #에서 가능합니까?

proclub 2020. 12. 30. 08:21
반응형

대리자로 생성자-C #에서 가능합니까?


다음과 같은 수업이 있습니다.

class Foo
{
  public Foo(int x) { ... }
}

다음과 같은 대리자를 특정 메서드에 전달해야합니다.

delegate Foo FooGenerator(int x);

FooGenerator입력하지 않고도 생성자를 값으로 직접 전달할 수 있습니까?

delegate(int x) { return new Foo(x); }

?

편집 : 개인적인 용도로 질문은 .NET 2.0을 참조하지만 3.0 이상에 대한 힌트 / 응답도 환영합니다.


아니요, CLR에서는 ConstructorInfo.

그러나 직접 만들 수 있습니다.

static T Make<T>(Action<T> init) where T : new()
{
  var t = new T();
  init(t);
  return t;
}

용법

var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });

실제 유형이 컴파일 타임에 알려지지 않은 공장 구현의 일부로 일반적으로 이와 같은 작업을 수행한다고 가정합니다.

먼저, 더 쉬운 접근 방식은 생성 후 초기화 단계 일 수 있으며 제네릭을 사용할 수 있습니다.

static T Create<T>({args}) where T : class, ISomeInitInterface, new() {
    T t = new T();
    t.Init(args);
    return t;
}

그런 다음 MakeGenericMethod및 / 또는 CreateDelegate.


그렇지 않으면; Expression(3.5) 또는 DynamicMethod(2.0) 을 사용하여 즉석에서이를 수행 할 수 있습니다 .

Expression접근 방식은 코딩하기가 더 쉽습니다.

    var param = Expression.Parameter(typeof(int), "val");
    var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    var lambda = Expression.Lambda<Func<int, Foo>>(
        Expression.New(ctor, param), param);
    var func = lambda.Compile();
    Foo foo = func(123);
    string s = foo.ToString(); // proof

또는 (사용 DynamicMethod) :

    ConstructorInfo ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    DynamicMethod dm = new DynamicMethod("Create", typeof(Foo),
            new Type[] { typeof(int) }, typeof(Foo), true);
    ILGenerator il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, ctor);
    il.Emit(OpCodes.Ret);
    Converter<int, Foo> func = (Converter<int, Foo>)
        dm.CreateDelegate(typeof(Converter<int, Foo>));        
    Foo foo = func(123);
    string s = foo.ToString(); // proof

(팩토리 패턴으로 이동하지 않고) 얻을 수있는 간결한 것은 다음과 같은 익명 메서드를 사용하는 것입니다.

delegate Foo FooGenerator(int x);

...    

void DoStuff()
{
    YourDelegateConsumer(x => new Foo(x));
}

이것은 당신이 요청한 것을 엄격하게 수행하지 않습니다 (생성자에 대한 직접 대리자가 아닌 새 인스턴스를 반환하는 익명 메서드에 대리자를 전달하기 때문입니다).하지만 나는 당신이 무엇을 요구하는지 생각하지 않습니다. 엄격히 가능합니다.

물론 이것은 3.5 이상을 사용하고 있다고 가정합니다.


아마도 클래스 팩토리 패턴을 사용하고 싶을 것 같습니다.

공장 방법 패턴


안타깝게도 생성자는 메서드와 동일한 것이 아니므로이를 가리키는 대리자를 만들 수 없습니다. 그러나 이것은 흥미로운 아이디어입니다. 아마도 더 많은 정보를 통해 우리는 구문 적으로 유사한 일종의 해결 방법을 고안 할 수있을 것입니다.


Marc Gravell의 답변은 다음과 같은 매우 간단한 솔루션에 영감을주었습니다.

static void Main()
{
    Pet a = _MakeObject(typeof(Dog));
    Pet b = _MakeObject(typeof(Cat));
}

private static Pet _MakeObject(Type type)
{
    ConstructorInfo info = type.GetConstructor(new Type[0]);
    return (Pet)info?.Invoke(null);
}

생성자에 매개 변수가있는 경우 거의 동일합니다 (이 예에서는 int 유형의 매개 변수 1 개).

static void Main()
{
    Pet a = _MakeObject(typeof(Dog), 5);
    Pet b = _MakeObject(typeof(Cat), 7);
}

private static Pet _MakeObject(Type type, int age)
{
    ConstructorInfo info = type.GetConstructor(new [] { typeof(int) });
    return (Pet)info?.Invoke(new object[] { age });
}

제 생각에는 아직 생성되지 않은 객체의 메서드를 전달하기 때문에 불가능하다는 것입니다.


또 다른 옵션은 다음 Activator과 같이 클래스 를 사용하는 것입니다 .

일반 유형 사용

public delegate Foo FooGeneratorDelegate<T>(int x);

public T FooGeneratorFunction<T>(int x)
{
    return (T)Activator.CreateInstance(typeof(T), x);
}

// implementation example
FooGeneratorDelegate<Foo> del = FooGeneratorFunction<Foo>;
Foo foo = del(someIntValue);

유형 Foo를 매개 변수로 전달

public delegate object FooGeneratorDelegate(Type t, int x);

public object FooGeneratorFunction(Type t, int x)
{
    return Activator.CreateInstance(t, x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = (Foo)del(typeof(Foo), someIntValue);

유형이 항상 유형 인 경우 Foo

public delegate Foo FooGeneratorDelegate(int x);

public Foo FooGeneratorFunction(int x)
{
    return (Foo)Activator.CreateInstance(typeof(Foo), x);
}

// implementation example
FooGeneratorDelegate del = FooGeneratorFunction;
Foo foo = del(someIntValue);

참조 URL : https://stackoverflow.com/questions/1600712/a-constructor-as-a-delegate-is-it-possible-in-c

반응형