सी # में base
का उपयोग केवल तत्काल आधार के लिए काम करता है। आप बेस-बेस सदस्य तक नहीं पहुंच सकते हैं।
ऐसा लगता है कि आईएल में ऐसा करने के बारे में उत्तर देने के साथ किसी और ने मुझे पंच को मार दिया।
हालांकि, मुझे लगता है कि जिस तरह से मैंने कोड जेन किया है उसके कुछ फायदे हैं, इसलिए मैं इसे किसी भी तरह पोस्ट करूंगा।
मैंने जो चीज अलग-अलग की थी वह अभिव्यक्ति पेड़ों का उपयोग करना है, जो आपको सी # कंपाइलर को ओवरलोड रिज़ॉल्यूशन और जेनेरिक तर्क प्रतिस्थापन करने के लिए उपयोग करने में सक्षम बनाता है।
वह सामान जटिल है, और यदि आप इसकी सहायता कर सकते हैं तो आप इसे स्वयं को दोहराना नहीं चाहते हैं। आपके मामले में, कोड इस तरह काम करेगा:
var del =
CreateNonVirtualCall<Program, BaseClass, Action<ThirdClass>>
(
x=>x.SayNo()
);
आप शायद एक केवल पढ़ने के लिए स्थिर क्षेत्र में प्रतिनिधि स्टोर करने के लिए, ताकि आप केवल एक बार यह संकलन करने के लिए है चाहेंगे। यह वर्ग है कि आप कोड लागू है | आप "CreateNonVirtualCall" का उपयोग नहीं कर रहे थे, तो से है -
मालिक के प्रकार:
आप 3 सामान्य तर्क निर्दिष्ट करने के लिए की जरूरत है।
आधार वर्ग - इस वर्ग आप से
एक प्रतिनिधि प्रकार गैर आभासी कॉल करनी है। यह "इस" तर्क के लिए अतिरिक्त पैरामीटर के साथ बुलाए जाने वाले विधि के हस्ताक्षर का प्रतिनिधित्व करना चाहिए। इसे खत्म करना संभव है, लेकिन कोड कोड विधि में इसे और अधिक काम की आवश्यकता है।
विधि एक एकल तर्क लेता है, एक लैम्ब्डा कॉल का प्रतिनिधित्व करता है। इसे एक कॉल होना चाहिए, और केवल एक कॉल होना है। यदि आप कोड जेन का विस्तार करना चाहते हैं तो आप अधिक जटिल सामग्री का समर्थन कर सकते हैं।
सादगी के लिए, लैम्ब्डा शरीर केवल लैम्ब्डा पैरामीटर तक पहुंचने में सक्षम है, और केवल उन्हें सीधे कार्य में ही पास कर सकता है। यदि आप सभी अभिव्यक्ति प्रकारों का समर्थन करने के लिए विधि निकाय में कोड जेन का विस्तार करते हैं तो आप इस प्रतिबंध को हटा सकते हैं। हालांकि यह कुछ काम करेगा। आप जो भी प्रतिनिधि चाहते हैं उसके साथ आप कुछ भी कर सकते हैं, इसलिए प्रतिबंध एक सौदे का बहुत बड़ा नहीं है।
यह ध्यान रखना महत्वपूर्ण है कि यह कोड सही नहीं है। यह बहुत अधिक सत्यापन का उपयोग कर सकता है, और यह अभिव्यक्ति वृक्ष सीमाओं के कारण "रेफरी" या "आउट" पैरामीटर के साथ काम नहीं करता है।
मैंने नमूना मामलों में शून्य विधियों, मूल्यों को वापस करने के तरीकों और सामान्य तरीकों के साथ परीक्षण किया, और यह काम किया। मुझे यकीन है कि, हालांकि, आप कुछ किनारे के मामलों को पा सकते हैं जो काम नहीं करते हैं।
किसी भी मामले में, यहाँ आईएल जनरल कोड है:
public static TDelegate CreateNonVirtCall<TOwner, TBase, TDelegate>(Expression<TDelegate> call) where TDelegate : class
{
if (! typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
{
throw new InvalidOperationException("TDelegate must be a delegate type.");
}
var body = call.Body as MethodCallExpression;
if (body.NodeType != ExpressionType.Call || body == null)
{
throw new ArgumentException("Expected a call expression", "call");
}
foreach (var arg in body.Arguments)
{
if (arg.NodeType != ExpressionType.Parameter)
{
//to support non lambda parameter arguments, you need to add support for compiling all expression types.
throw new ArgumentException("Expected a constant or parameter argument", "call");
}
}
if (body.Object != null && body.Object.NodeType != ExpressionType.Parameter)
{
//to support a non constant base, you have to implement support for compiling all expression types.
throw new ArgumentException("Expected a constant base expression", "call");
}
var paramMap = new Dictionary<string, int>();
int index = 0;
foreach (var item in call.Parameters)
{
paramMap.Add(item.Name, index++);
}
Type[] parameterTypes;
parameterTypes = call.Parameters.Select(p => p.Type).ToArray();
var m =
new DynamicMethod
(
"$something_unique",
body.Type,
parameterTypes,
typeof(TOwner)
);
var builder = m.GetILGenerator();
var callTarget = body.Method;
if (body.Object != null)
{
var paramIndex = paramMap[((ParameterExpression)body.Object).Name];
builder.Emit(OpCodes.Ldarg, paramIndex);
}
foreach (var item in body.Arguments)
{
var param = (ParameterExpression)item;
builder.Emit(OpCodes.Ldarg, paramMap[param.Name]);
}
builder.EmitCall(OpCodes.Call, FindBaseMethod(typeof(TBase), callTarget), null);
if (body.Type != typeof(void))
{
builder.Emit(OpCodes.Ret);
}
var obj = (object) m.CreateDelegate(typeof (TDelegate));
return obj as TDelegate;
}
आप अपने वर्गों में से एक के लिए इरादा था BasClass से प्राप्त करना (SecondClass कहते हैं)? –
कोई नहीं; जोड़ने या बदलने के लिए और कक्षाएं नहीं ... – henry000