استدعاء Methodbase's استدعاء على مُنشئ (انعكاس)
-
23-09-2019 - |
سؤال
بادئ ذي بدء ، آسف إذا تم طلب ذلك من قبل. لقد أجريت بحثًا شاملاً ولم أجد شيئًا مثله تمامًا ، لكنني ربما فاتني شيء ما.
والآن على السؤال: أحاول استدعاء مُنشئ من خلال التفكير ، دون حظ. في الأساس ، لدي كائن أريد استنساخه ، لذلك أبحث عن مُنشئ النسخ لنوعه ثم أريد استدعاءه. هذا ما لدي:
public Object clone(Object toClone) {
MethodBase copyConstructor = type.GetConstructor(
new Type[] { toClone.GetType() });
return method.Invoke(toClone, new object[] { toClone }); //<-- doesn't work
}
أسمي الطريقة أعلاه مثل ذلك:
List<int> list = new List<int>(new int[] { 0, 1, 2 });
List<int> clone = (List<int>) clone(list);
الآن ، لاحظ أن طريقة الاستدعاء التي أستخدمها هي MethodBase
استدعاء. ConstructorInfo
يوفر طريقة استدعاء تعمل إذا تم الاحتجاج بها مثل هذا:
return ((ConstructorInfo) method).Invoke(new object[] { toClone });
ومع ذلك ، أريد استخدام MethodBase
طريقة ، لأنه في الواقع بدلاً من البحث عن مُنشئ النسخ في كل مرة سأقوم فيها بتخزينها في القاموس ، ويحتوي القاموس على كل من الأساليب والمقدمات ، لذا فهو أ Dictionary<MethodBase>
, ، ليس Dictionary<ConstructorInfo>
. يمكنني بالطبع أن ألقي في ConstructorInfo
كما أفعل أعلاه ، لكنني أفضل تجنب الصب واستخدام MethodBase
الطريقة مباشرة. لا يمكنني معرفة المعلمات الصحيحة.
أي مساعدة؟ ًشكراً جزيلا.
تعديل
بنيامين،
شكرا جزيلا لاقتراحاتكم. كنت أفعل ما تقترحه بالضبط في التحرير الثاني ، باستثناء (وهذا "كبير" باستثناء ") كان القاموس الخاص بي هو المكان
class ClonerMethod {
public MethodBase method;
public bool isConstructor;
...
public Object invoke(Object toClone) {
return isConstructor ?
((ConstructorInfo) method).Invoke(new object[] { toClone }) : //<-- I wanted to avoid this cast
method.Invoke(toClone, null);
}
}
ثم اتصلت ClonerMethod
'س invoke
على ما وجدته في القاموس. لم أضف الكود الصفقات مع كل ذلك لأن الإجابة التي كنت أبحث عنها كانت مجرد كيفية الاتصال بالاستدعاء على أ ConstructorInfo
استخدام MethodBase
'س Invoke
الطريقة ، لذلك لم أكن أرغب في إضافة معلومات غير ضرورية والكثير من التعليمات البرمجية لكم يا رفاق لقراءتها. ومع ذلك ، أحب استخدامك Func<,>
أفضل بكثير ، لذلك أنا أتحول إلى ذلك. أيضا جعل Clone
الطريقة العامة هي إضافة لطيفة ، ولكن في حالتي ، لا يعرف المتصل نوع الكائن ، لذلك سأبقيه غير واضحة بدلاً من ذلك.
لم أكن أعرف عنه Func<,>
, ، وإذا علمت عن مشغل Lambda الذي نسيته (لم أكن بحاجة حقًا إلى شيء مثل هذا من قبل) ، لذلك تعلمت الكثير من إجابتك. أحب دائمًا أن أتعلم أشياء جديدة ، وسيكون هذا مفيدًا جدًا في المستقبل ، لذا شكرًا جزيلاً! قون
المحلول
إذا كنت تعلم أن الكائن لديه مُنشئ من هذا القبيل ، هل فكرت في استخدام هذا الحمل الزائد Activator.CreateInstance
في حين أن؟
تحديث: لذلك لديك بحث متتالي عن MethodInfo/Methodbase بالفعل وتخزينها -> لا تريد/لا يمكنك استخدامها Activator
.
في هذه الحالة ، لا أرى طريقة لفعل ما تريد بدون طاقم. ولكن - ربما يمكنك تغيير الهندسة المعمارية لتخزين أ Dictionary<Type, Func<object, object>>
وإضافة تلك Func<>
حالات بدلا من ذلك. يجعل رمز الاتصال أجمل (أفترض) وسيسمح لك بالقيام بهذا المدلى بها مرة واحدة:
// Constructor
dictionary.Add(type,
source => ((ConstructorInfo) method).Invoke(new object[] {source})
);
// Clone
dictionary.Add(type,
source => method.Invoke(source, new object[]{})
);
في الواقع ، نظرًا لأنك تهتم فقط بالفرق بين المنشئ والطريقة العادية في الموقع الذي تمسك به ، فلن تحتاج إلى ممثلين على الإطلاق ، أليس كذلك؟
// Constructor 2
dictionary.Add(type,
source => yourConstructorInfo.Invoke(new object[] {source})
);
ما لم أكن أفتقد شيئًا (ممكنًا تمامًا ، بالطبع) ، يمكن أن يحل هذا المشكلة عن طريق القيام بذلك مرة واحدة على الجانب المحدد من السياج ولن يحتاج المتصل إلى الثقل إذا كان هذا مُنشئًا أم لا؟
آخر مرة ، ثم سأوقف التعديل غير المرغوب فيه. شعرت بالملل وتوصلت إلى الكود التالي. هل هذا ما تحاول إنجازه؟
public class Cloner {
private readonly IDictionary<Type, Func<object, object>> _cloneMap =
new Dictionary<Type, Func<object, object>>();
public T Clone<T>(T source) {
Type sourceType = source.GetType();
Func<object, object> cloneFunc;
if (_cloneMap.TryGetValue(sourceType, out cloneFunc)) {
return (T)cloneFunc(source);
}
if (TryGetCopyConstructorCloneFunc(sourceType, out cloneFunc)) {
_cloneMap.Add(sourceType, cloneFunc);
return (T)cloneFunc(source);
}
if (TryGetICloneableCloneFunc(sourceType, out cloneFunc)) {
_cloneMap.Add(sourceType, cloneFunc);
return (T)cloneFunc(source);
}
return default(T);
}
private bool TryGetCopyConstructorCloneFunc(Type type,
out Func<object, object> cloneFunc) {
var constructor = type.GetConstructor(new[] { type });
if (constructor == null) {
cloneFunc = source => null;
return false;
}
cloneFunc = source => constructor.Invoke(new[] { source });
return true;
}
private bool TryGetICloneableCloneFunc(Type type,
out Func<object, object> cloneFunc) {
bool isICloneable = typeof(ICloneable).IsAssignableFrom(type);
var cloneMethod = type.GetMethod("Clone", new Type[] { });
if (!isICloneable || (cloneMethod == null)) {
cloneFunc = source => null;
return false;
}
cloneFunc = source => cloneMethod.Invoke(source, new object[] {});
return true;
}
}