قم بإنشاء مندوب من مُنشئ من النوع غير المعروف ينفذ واجهة معروفة

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

سؤال

لدي نوع يتم إنشاؤه في وقت التشغيل (من خلال التجميع من Codedom) ويقوم بتنفيذ واجهة معروفة (في وقت الترجمة).

لنفترض أن الواجهة IMyInterface, ، ولدي مثيل النوع Type myType لقد اكتسبت من التجميع الذي قمت بتجميعه للتو من codedom. الفصل الذي myType يمثل الأدوات IMyInterface.

أود الحصول على مندوب Func<IMyInterface> ذلك ، عند الاحتجاج ، سيعود مثيلًا myType.

شيء أود الاتصال به بهذه الطريقة:

Func<IMyInterface> createObject = GetObjectCreator<IMyInterface>(myType);
IMyInterface myObject = createObject();

أعلم أنه إذا كان لدي MethodInfo m للحصول على طريقة غير معلمة تُرجع مثيلًا لكائن mytype ، ثم يمكنني فعل شيء مثل هذا:

Func<IMyInterface> createObject =
  ( Func<IMyInterface> )Delegate.CreateDelegate(typeof(Func<IMyInterface>), m);

ولكن إذا لم يكن لدي مثل هذه الطريقة ، والشيء الوحيد الذي لدي هو مُنشئ النوع بدون معلمة ، فكيف أحصل على هذا المندوب؟

تحديث

على الرغم من أن إجابة Fsimonazzi فعلت بالضبط ما كنت أطلبه ، إلا أن نهائي كان مختلفًا بعض الشيء.

منذ أن أتحكم في إنشاء وتجميع myType اكتب ، أضفت طريقة ثابتة عامة تُرجع مثيلًا لهذا النوع. بعد ذلك ، بعد تجميع هذا النوع ، حصلت على مثيل MethodInfo لهذه الطريقة ، وقمت بإنشاء مندوب الاتصال المطلوب.

CodeTypeDeclaration type = new CodeTypeDeclaration
{
    Name = "MyClass",
    IsClass = true,
    TypeAttributes = TypeAttributes.Public
};

type.BaseTypes.Add(new CodeTypeReference(typeof(IMyInterface)));

// fullName is the full name of the myType (including namespace)
var staticInstantiator = new CodeMemberMethod
{
    Name = "__Instantiator",
    ReturnType = new CodeTypeReference("MyNamespace.MyClass"),
    Attributes = MemberAttributes.Public | MemberAttributes.Static
};

staticInstantiator.Statements.Add(
   new CodeMethodReturnStatement(
       new CodeObjectCreateExpression("MyNamespace.MyClass")));

    type.Members.Add(staticInstantiator);

يولد الرمز أعلاه هذا الرمز ويضع في إعلان الفصل

public static MyNamespace.MyClass __Instantiator()
{
    return new MyNamespace.MyClass();
}

الآن تجميع هذا الرمز والحصول على ملف myType اكتب مثيلًا لهذه الفئة ، يمكنني القيام بذلك

Func<IMyInterface> createObject = ( Func<IMyInterface> )(
    Delegate.CreateDelegate(typeof(Func<IMyInterface>),
                            myType.GetMethod("__Instantiator")) );

IMyInterface obj = createObject(); // This will call MyClass.__Instantiator()
هل كانت مفيدة؟

المحلول

يمكنك تجميع تعبير Lambda بسيط للحصول على مندوب الخاص بك.

var del = Expression.Lambda<Func<IMyInterface>>(Expression.New(type)).Compile();

نصائح أخرى

يمكنك استخدام Activator.CreateInstance( type ) لإنشاء مثيل من نوعك بالفعل. إذا كنت تريد هذا محشوة في Func<IMyInterface> ثم يمكنك فقط لفه في Lambda:

Func<IMyInterface> createObject = () => (IMyInterface) Activator.CreateInstance( myType );
IMyInterface myObject = createObject();

تحديث:

حيث Activator.CreateInstance من الواضح أنه ليس ما تبحث عنه (على الرغم من أنني لست متأكدًا تمامًا من السبب) ، أفترض أنه يمكنك استخدام الانعكاس للعثور على مُنشئ بدون معلمة من النوع:

public Func<T> GetObjectCreator<T>( Type type )
{
    // I'd probably add additional checks here to see that the
    // conversion to T is actually possible.

    var ctor = type.GetConstructor( Type.EmptyTypes );

    if( ctor == null ) throw new ArgumentException( "type", "Public parameterless constructor not found." )

    return () => (T) ctor.Invoke( null );
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top