Tôi đang làm việc trên một thư viện cho phép người dùng nhập các biểu thức tùy ý. Thư viện của tôi sau đó biên dịch các biểu thức như một phần của một biểu thức lớn hơn thành một đại biểu. Bây giờ, vì những lý do vẫn chưa biết, việc biên dịch biểu thức với Compile
đôi khi/thường dẫn đến mã chậm hơn nhiều so với nếu nó không phải là một biểu thức được biên dịch. Tôi asked a question about this trước đây và một giải pháp khác là không sử dụng Compile
, nhưng CompileToMethod
và tạo phương thức static
trên một loại mới trong một hội động mới. Điều đó hoạt động và mã nhanh. Tuy nhiên, người dùng có thể nhập các biểu thức tùy ý và nó chỉ ra rằng nếu người dùng gọi một chức năng ngoài công lập hoặc truy cập một trường ngoài công khai trong biểu thức, nó sẽ ném một số System.MethodAccessException
(trong trường hợp của một phương thức phi công cộng). khi đại biểu được gọi. Những gì tôi có thể làm ở đây là tạo ExpressionVisitor
mới để kiểm tra xem biểu thức có truy cập bất kỳ điều gì không công khai và sử dụng chậm hơn Compile
trong những trường hợp đó hay không, nhưng tôi muốn có các thành viên ngoài công lập. Hoặc tìm hiểu xem có bất kỳ điều gì tôi có thể làm về số Compile
chậm hơn (đôi khi) hay không..NET: Truy cập các thành viên ngoài công lập từ một assembly động
Mã đầy đủ để tái tạo vấn đề này:
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;
}
}
}
Tôi không có câu trả lời cho bạn, nhưng tại sao cần hỗ trợ gọi các phương thức riêng tư? – jlew
Bởi vì người dùng hy vọng nó sẽ là có thể. Bởi vì chúng * có thể truy cập được khi anh ta tạo ra biểu thức, như '() => CallPrivateMethod()', nhưng chúng sẽ thất bại khi chạy. Không có gì để anh ta chỉ ra rằng nó không hoạt động cho đến khi anh ta chạy nó và nó bị treo và bỏng. Đó là thực sự xấu và vi phạm các quy tắc của "ít ngạc nhiên" vì vậy tôi không thể biện minh làm điều đó và tôi sẽ phải giải quyết cho mã chậm. – JulianR
Làm cho tinh thần, nếu người dùng là một lập trình viên C# (như trái ngược với ai đó gõ biểu thức vào một hình thức, ví dụ). Bạn đã chuẩn bị bản phát hành so với chế độ gỡ lỗi cho đại biểu được biên soạn chưa? Làm thế nào để họ so sánh với nhau? – jlew