object o = ...;
Func<object> sneaky =() => o;
gen.Emit(OpCodes.Call, sneaky.Method);
एक तरफ ध्यान दें, सुनिश्चित करें कि आप अपने उद्देश्य के लिए System.Linq.Expressions का उपयोग नहीं कर सकते हैं। पहले और बाद में एएनटीएलआर परियोजना में मेरे कोड का एक अनुभाग यहां दिया गया है:
इससे पहले। ध्यान दें कि इसमें एक बग है (इसके बारे में मेलिंग सूची पोस्ट नहीं मिल रहा है) कि मुझे यह नहीं मिला क्योंकि "बाद में" स्विच को साइड इफेक्ट के रूप में सही किया गया था।
private static Func<object, object> BuildAccessor(MethodInfo method)
{
DynamicMethod dm = new DynamicMethod(method.DeclaringType.Name + method.Name + "MethodAccessor", typeof(object), new Type[] { typeof(object) }, method.DeclaringType);
var gen = dm.GetILGenerator();
if (!method.IsStatic)
{
gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
gen.Emit(System.Reflection.Emit.OpCodes.Castclass, method.DeclaringType);
}
if (method.IsVirtual && !method.IsFinal)
gen.EmitCall(System.Reflection.Emit.OpCodes.Callvirt, method, null);
else
gen.EmitCall(System.Reflection.Emit.OpCodes.Call, method, null);
if (method.ReturnType.IsValueType)
gen.Emit(System.Reflection.Emit.OpCodes.Box, method.ReturnType);
gen.Emit(System.Reflection.Emit.OpCodes.Ret);
return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
}
private static Func<object, object> BuildAccessor(FieldInfo field)
{
DynamicMethod dm = new DynamicMethod(field.DeclaringType.Name + field.Name + "FieldAccessor", typeof(object), new Type[] { typeof(object) }, field.DeclaringType);
var gen = dm.GetILGenerator();
if (field.IsStatic)
{
gen.Emit(System.Reflection.Emit.OpCodes.Ldsfld, field);
}
else
{
gen.Emit(System.Reflection.Emit.OpCodes.Ldarg_0);
gen.Emit(System.Reflection.Emit.OpCodes.Castclass, field.DeclaringType);
gen.Emit(System.Reflection.Emit.OpCodes.Ldfld, field);
}
if (field.FieldType.IsValueType)
gen.Emit(System.Reflection.Emit.OpCodes.Box, field.FieldType);
gen.Emit(System.Reflection.Emit.OpCodes.Ret);
return (Func<object, object>)dm.CreateDelegate(typeof(Func<object, object>));
}
के बाद:
private static Func<object, object> BuildAccessor(MethodInfo method)
{
ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method),
typeof(object)),
obj);
return expr.Compile();
}
private static Func<object, object> BuildAccessor(FieldInfo field)
{
ParameterExpression obj = Expression.Parameter(typeof(object), "obj");
Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Field(
Expression.Convert(obj, field.DeclaringType),
field),
typeof(object)),
obj);
return expr.Compile();
}
इसका परिणाम एक विधिAccessException में होता है क्योंकि स्थानीय रूप से परिभाषित लैम्ब्डा नई विधि में उपलब्ध नहीं है। – shivak
यह दिलचस्प है, क्योंकि यह वही है जो मैं अपने प्रयोगात्मक स्ट्रिंग टेम्पलेट कंपाइलर में करता हूं (और यह वहां काम करता है)। –
क्षमा करें, मेरा मतलब है कि उत्सर्जित नई असेंबली से पहुंच योग्य नहीं है। वहां उपलब्ध एक संदर्भ प्रकार बनाना अनुचित लगता है और इसलिए मैंने शुरुआत में महसूस किया कि एक क्लज आवश्यक होगा। – shivak