मैं एक लाइब्रेरी पर काम कर रहा हूं जो उपयोगकर्ताओं को मनमाने ढंग से अभिव्यक्तियों को इनपुट करने की अनुमति देता है। मेरी लाइब्रेरी तब उन अभिव्यक्तियों को एक प्रतिनिधि में एक बड़ी अभिव्यक्ति के हिस्से के रूप में संकलित करती है। अब, Compile
के साथ अभिव्यक्ति को संकलित करने के अभी भी अज्ञात कारणों के लिए कभी-कभी/अक्सर कोड में परिणाम होता है जो उससे धीमा होता है यदि यह संकलित अभिव्यक्ति नहीं होता है। I asked a question about this पहले और एक वर्कअराउंड Compile
का उपयोग नहीं करना था, लेकिन CompileToMethod
और नई गतिशील असेंबली में एक नए प्रकार पर static
विधि बनाएं। वह काम करता है और कोड तेज़ है।.NET: गतिशील असेंबली से गैर-सार्वजनिक सदस्यों तक पहुंच
लेकिन उन इनपुट कर सकते हैं मनमाना भाव और यह है कि उपयोगकर्ता एक गैर सरकारी समारोह कॉल या अभिव्यक्ति में एक गैर सरकारी क्षेत्र तक पहुँचता है, यह एक System.MethodAccessException
(एक गैर सरकारी विधि के मामले में) फेंकता है पता चला है जब प्रतिनिधि को बुलाया जाता है।
मैं शायद यहां क्या कर सकता हूं एक नया ExpressionVisitor
बनाता है जो जांचता है कि अभिव्यक्ति गैर-सार्वजनिक पहुंचती है और उन मामलों में धीमी Compile
का उपयोग करती है, लेकिन मुझे लगता है कि गतिशील असेंबली किसी भी तरह से पहुंच का अधिकार प्राप्त करेगी गैर-सार्वजनिक सदस्य। या पता लगाएं कि क्या कुछ भी है जो मैं Compile
धीमा (कभी-कभी) होने के बारे में कर सकता हूं।
पूर्ण कोड इस समस्या को पुन: पेश करने:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
namespace DynamicAssembly
{
public class Program
{
private static int GetValue()
{
return 1;
}
public static int GetValuePublic()
{
return 1;
}
public static int Foo;
static void Main(string[] args)
{
Expression<Func<int>> expression =() => 10 + GetValue();
Foo = expression.Compile()();
Console.WriteLine("This works, value: " + Foo);
Expression<Func<int>> expressionPublic =() => 10 + GetValuePublic();
var compiledDynamicAssemblyPublic = (Func<int>)CompileExpression(expressionPublic);
Foo = compiledDynamicAssemblyPublic();
Console.WriteLine("This works too, value: " + Foo);
var compiledDynamicAssemblyNonPublic = (Func<int>)CompileExpression(expression);
Console.WriteLine("This crashes");
Foo = compiledDynamicAssemblyNonPublic();
}
static Delegate CompileExpression(LambdaExpression expression)
{
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("MyAssembly"+ Guid.NewGuid().ToString("N")),
AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public);
var methodBuilder = typeBuilder.DefineMethod("MyMethod",
MethodAttributes.Public | MethodAttributes.Static);
expression.CompileToMethod(methodBuilder);
var resultingType = typeBuilder.CreateType();
var function = Delegate.CreateDelegate(expression.Type,
resultingType.GetMethod("MyMethod"));
return function;
}
}
}
मेरे पास आपके लिए कोई जवाब नहीं है, लेकिन निजी तरीकों को कॉल करने का समर्थन करना क्यों आवश्यक है? – jlew
क्योंकि उपयोगकर्ता अपेक्षा करता है कि यह संभव होना चाहिए। क्योंकि वे अभिव्यक्ति बनाता है, जब वे अभिव्यक्ति बनाता है, जैसे '() => CallPrivateMethod() ', लेकिन वे रनटाइम पर असफल हो जाएंगे। उसके पास कुछ भी नहीं है जो इंगित करेगा कि यह तब तक काम नहीं करता जब तक वह इसे चलाता है और यह दुर्घटनाग्रस्त हो जाता है और जलता है। यह वास्तव में बुरा है और "कम से कम आश्चर्य" के नियम का उल्लंघन करता है, इसलिए मैं ऐसा करने का औचित्य सिद्ध नहीं कर सकता और मुझे धीमे कोड के लिए बसना होगा। – JulianR
समझ में आता है, यदि उपयोगकर्ता एक सी # प्रोग्रामर है (उदाहरण के लिए किसी रूप में अभिव्यक्ति टाइप करने वाले किसी के विपरीत)। क्या आपने संकलित प्रतिनिधि के लिए रिलीज बनाम डीबग मोड बेंचमार्क किया है? वे एक दूसरे के साथ तुलना कैसे करते हैं? – jlew