c# - 在 C# 中使用表达式创建通用委托(delegate)

标签 c# generics delegates lambda expression

下面给出了两种创建委托(delegate)来设置类中字段的方法。一种方法使用泛型,另一种不使用。 这两种方法都返回一个委托(delegate),并且它们工作正常。但是,如果我尝试使用在 CreateDelegate 方法中创建的委托(delegate),则非通用委托(delegate)“del”可以正常工作。我可以在返回语句上放置一个断点并通过编写 del(222) 来调用委托(delegate)。但是,如果我尝试通过编写 genericDel(434) 来调用通用委托(delegate)“genericDel”,它会抛出异常:

Delegate 'System.Action' has some invalid arguments

谁能解释一下这个怪癖。

class test
{
    public double fld = 0;
}

public static void Main(string[] args)
{
    test tst = new test() { fld = 11 };

    Type myType = typeof(test);
    // Get the type and fields of FieldInfoClass.
    FieldInfo[] myFieldInfo = myType.GetFields(BindingFlags.Instance | BindingFlags.Public);
    var a = CreateDelegate<double>(myFieldInfo[0], tst);
    var b = CreateDelegate(myFieldInfo[0], tst);

    Console.WriteLine(tst.fld);

    b(5.0);
    Console.WriteLine(tst.fld);

    a(6.0);
    Console.WriteLine(tst.fld);
}

public static Action<T> CreateDelegate<T>(FieldInfo fieldInfo, object instance)
{
    ParameterExpression numParam = Expression.Parameter(typeof(T), "num");
    Expression a = Expression.Field(Expression.Constant(instance), fieldInfo);
    BinaryExpression assExp = Expression.Assign(a, numParam);

    Expression<Action<T>> expTree =
        Expression.Lambda<Action<T>>(assExp,
            new ParameterExpression[] { numParam });

    Action<T> genericDel = expTree.Compile();
    //try to invoke the delegate from immediate window by placing a breakpoint on the return below: genericDel(323)
    return genericDel;
}

public static Action<double> CreateDelegate(FieldInfo fieldInfo, object instance)
{
    ParameterExpression numParam = Expression.Parameter(typeof(double), "num");
    Expression a = Expression.Field(Expression.Constant(instance), fieldInfo);
    BinaryExpression assExp = Expression.Assign(a, numParam);

    Expression<Action<double>> expTree =
        Expression.Lambda<Action<double>>(assExp,
            new ParameterExpression[] { numParam });

    Action<double> del = expTree.Compile();
    //try to invoke the delegate from immediate window by placing a breakpoint on the return below: del(977)
    return del;
}

最佳答案

我想我理解了这个问题;当委托(delegate)的编译时类型 是开放泛型类型时,您在从即时窗口调用泛型委托(delegate)时遇到问题。 这是一个更简单的重现:

  static void Main() { Test<double>(); }

  static void Test<T>()
  {
        Action<T> genericDel = delegate { };
       // Place break-point here.
  }

现在,如果我尝试从 Test 中执行这个委托(delegate)方法(通过放置断点并使用即时窗口)如下所示:

genericDel(42D);

我收到以下错误:

Delegate 'System.Action<T>' has some invalid arguments

请注意,这不是您所说的异常,而是compile-time error CS1594 的“即时窗口版本” .

请注意,这样的调用在编译时同样会失败,因为没有从 double 进行隐式或显式转换。至 T .

这是有争议的即时窗口的一个缺点(在这种情况下它似乎不愿意使用额外的“运行时知识”来帮助你),但有人可能会争论这是合理的行为,因为在编译时(在源代码中)进行的等效调用也是非法的。不过,这确实是一个极端案例;立即窗口完全能够分配通用变量并执行其他在编译时非法的代码。或许 Roslyn 会让事情变得更加一致。

如果你愿意,你可以像这样解决这个问题:

genericDel.DynamicInvoke(42D);

(或)

((Action<double>)(object)genericDel)(42D);

关于c# - 在 C# 中使用表达式创建通用委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7857927/

相关文章:

ios - 实现从 viewController 到 DataManager 类的委托(delegate)

c# - Entity Framework Code First,不同上下文/数据库之间的导航属性

c# - 如何更改现有事件处理程序的名称?

c# - 如何同时更新 32 位和 64 位 machine.config

swift - 有没有一些方法可以检查类是否是从泛型类型继承的?

swift - 在没有 Storyboard的情况下从 collectionView 显示 viewController

c# - 我如何将值传递给 Controller

scala - 如何引用更高种类的类型参数的参数?

c# - 如何将与特定 C# 接口(interface)匹配的所有类型放入 IDictionary 中?

c# - 当委托(delegate)可以完成工作时,事件有什么用