대의원으로서의 생성자 - C#에서 가능합니까?
-
05-07-2019 - |
문제
아래와 같은 수업이 있습니다.
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);
}
생성자가 매개 변수가있는 경우 (이 예에서 : 1 유형 int의 매개 변수) :
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 });
}
내 생각에 아직 생성되지 않은 객체의 방법을 통과하기 때문에 불가능하다는 것입니다.