gpt4 book ai didi

c# - 在 C# 中,Expression API 是否比 Reflection 更好

转载 作者:IT王子 更新时间:2023-10-29 03:55:37 26 4
gpt4 key购买 nike

现在,我正在研究 C# Expression API。所以我可以使用一些帮助来理解它是如何工作的,包括表达式和反射之间的区别。我还想了解表达式是否只是句法糖分,还是它们确实比反射更好性能方面

我们将不胜感激很好的例子以及指向好的文章的链接。 :-)

最佳答案

关于调用一个方法:

  • 直接调用在速度方面无可匹敌。
  • 使用 Expression API 在全局上类似于使用 Reflection.EmitDelegate.CreateDelegate 速度方式(可以测量微小差异;一如既往地优化速度没有衡量标准和目标是没有用的)。

    它们都生成 IL,框架会在某个时候将其编译为 native 代码。但是您仍然需要为调用委托(delegate)和委托(delegate)内部的一种方法调用支付一个间接级别的成本。

    表达式 API 更受限制,但使用起来更简单一个数量级,因为它不需要您学习 IL。

  • 直接使用或通过 C# 4 的 dynamic 关键字使用的动态语言运行时增加了一点开销,但接近发出代码,因为它缓存了与参数类型、访问和休息。

    当通过 dynamic 关键字使用时,它还获得了最简洁的语法,因为它看起来像一个普通的方法调用。但是,如果您使用动态,则仅限于方法调用,而库可以做更多的事情(参见 IronPython)

  • System.Reflection.MethodInfo.Invoke 很慢:除了其他方法之外,它还需要检查访问权限、检查参数计数、类型……针对 MethodInfo 每次调用该方法时。

Jon Skeet 在这个答案中也有一些优点:Delegate.CreateDelegate vs DynamicMethod vs Expression


一些示例,同样的事情以不同的方式完成。

您已经可以从行数和复杂性中看出哪些解决方案易于维护,哪些从长期维护的角度来看应该避免。

大多数示例毫无意义,但它们演示了 C# 的基本代码生成类/语法,有关更多信息,请访问 MSDN

PS:转储是一个LINQPad方法。

public class Foo
{
public string Bar(int value) { return value.ToString(); }
}

void Main()
{
object foo = new Foo();

// We have an instance of something and want to call a method with this signature on it :
// public string Bar(int value);

Console.WriteLine("Cast and Direct method call");
{
var result = ((Foo)foo).Bar(42);
result.Dump();
}
Console.WriteLine("Create a lambda closing on the local scope.");
{
// Useless but i'll do it at the end by manual il generation

Func<int, string> func = i => ((Foo)foo).Bar(i);
var result = func(42);
result.Dump();
}
Console.WriteLine("Using MethodInfo.Invoke");
{
var method = foo.GetType().GetMethod("Bar");
var result = (string)method.Invoke(foo, new object[] { 42 });
result.Dump();
}
Console.WriteLine("Using the dynamic keyword");
{
var dynamicFoo = (dynamic)foo;
var result = (string)dynamicFoo.Bar(42);
result.Dump();
}
Console.WriteLine("Using CreateDelegate");
{
var method = foo.GetType().GetMethod("Bar");
var func = (Func<int, string>)Delegate.CreateDelegate(typeof(Func<int, string>), foo, method);
var result = func(42);
result.Dump();
}
Console.WriteLine("Create an expression and compile it to call the delegate on one instance.");
{
var method = foo.GetType().GetMethod("Bar");
var thisParam = Expression.Constant(foo);
var valueParam = Expression.Parameter(typeof(int), "value");
var call = Expression.Call(thisParam, method, valueParam);
var lambda = Expression.Lambda<Func<int, string>>(call, valueParam);
var func = lambda.Compile();
var result = func(42);
result.Dump();
}
Console.WriteLine("Create an expression and compile it to a delegate that could be called on any instance.");
{
// Note that in this case "Foo" must be known at compile time, obviously in this case you want
// to do more than call a method, otherwise just call it !
var type = foo.GetType();
var method = type.GetMethod("Bar");
var thisParam = Expression.Parameter(type, "this");
var valueParam = Expression.Parameter(typeof(int), "value");
var call = Expression.Call(thisParam, method, valueParam);
var lambda = Expression.Lambda<Func<Foo, int, string>>(call, thisParam, valueParam);
var func = lambda.Compile();
var result = func((Foo)foo, 42);
result.Dump();
}
Console.WriteLine("Create a DynamicMethod and compile it to a delegate that could be called on any instance.");
{
// Same thing as the previous expression sample. Foo need to be known at compile time and need
// to be provided to the delegate.

var type = foo.GetType();
var method = type.GetMethod("Bar");

var dynamicMethod = new DynamicMethod("Bar_", typeof(string), new [] { typeof(Foo), typeof(int) }, true);
var il = dynamicMethod.GetILGenerator();
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Ret);
var func = (Func<Foo, int, string>)dynamicMethod.CreateDelegate(typeof(Func<Foo, int, string>));
var result = func((Foo)foo, 42);
result.Dump();
}
Console.WriteLine("Simulate closure without closures and in a lot more lines...");
{
var type = foo.GetType();
var method = type.GetMethod("Bar");

// The Foo class must be public for this to work, the "skipVisibility" argument of
// DynamicMethod.CreateDelegate can't be emulated without breaking the .Net security model.

var assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("MyAssembly"), AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule("MyModule");
var tb = module.DefineType("MyType", TypeAttributes.Class | TypeAttributes.Public);

var fooField = tb.DefineField("FooInstance", type, FieldAttributes.Public);
var barMethod = tb.DefineMethod("Bar_", MethodAttributes.Public, typeof(string), new [] { typeof(int) });
var il = barMethod.GetILGenerator();
il.DeclareLocal(typeof(string));
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldfld, fooField);
il.Emit(OpCodes.Ldarg_1); // arg
il.Emit(OpCodes.Call, method);
il.Emit(OpCodes.Ret);

var closureType = tb.CreateType();

var instance = closureType.GetConstructors().Single().Invoke(new object[0]);

closureType.GetField(fooField.Name).SetValue(instance, foo);

var methodOnClosureType = closureType.GetMethod("Bar_");

var func = (Func<int, string>)Delegate.CreateDelegate(typeof(Func<int, string>), instance,
closureType.GetMethod("Bar_"));
var result = func(42);
result.Dump();
}
}

关于c# - 在 C# 中,Expression API 是否比 Reflection 更好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4803272/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com