【问题标题】:Get Method Name Using Lambda Expression使用 Lambda 表达式获取方法名称
【发布时间】:2010-02-22 21:25:49
【问题描述】:

我正在尝试使用 lambda 表达式获取类型上的方法名称。我正在使用 Windows Identity Foundation,需要使用命名空间作为资源的类型名称和作为操作的方法名称来定义访问策略。这是一个例子。

这是我要从中获取类型名称和方法名称的类型:

namespace My.OrderEntry {
    public class Order {
        public void AddItem(string itemNumber, int quantity) {}
    }
}

这就是我想通过 DSL 定义访问策略的方式:

ForResource<Order>().Performing(o => o.AddItem).AllowUsersHaving(new Claim());

从该声明中,我想将“My.OrderEntry.Order”作为资源,将“AddItem”作为操作。使用命名空间获取类型名称没有问题,但我认为我不能将 lambda 用于我正在尝试做的方法。

public static IPermissionExp Performing<T>(
    this IActionExp<T> exp,
    Func<T, delegate???> action) {} //this is where I don't know what to define

这种事情甚至可以做到吗?有没有其他方法可以在不使用魔术字符串的情况下做这种事情?

【问题讨论】:

  • AddItem 应该添加什么?
  • AddItem 做什么并不重要,我只需要方法的名称而不使用魔术字符串。
  • 这很重要。我认为你要去的地方是一个 Action 但我认为这不是最好的答案。
  • 可以做Action吗?我真的只需要获取方法名称来定义是否允许用户在该类型(资源)上调用该方法(操作)。
  • 好的,我明白你现在想要做什么了。还有一个问题 - 传递给 AddItem 的值从何而来?

标签: c# reflection lambda


【解决方案1】:

有两种方法可以做到这一点:

1:您可以使用各种FuncAction 委托进行重载(例如Expression&lt;Func&lt;T, Func&lt;TParam1,TParam2, TReturn&gt;&gt;。请注意,您的调用者需要在方法调用中或通过创建委托来显式指定泛型参数. 这将像这样使用:

ForResource<Order>().Performing(o => new Action<string>(o.AddItem)).AllowUsersHaving(new Claim());

2:您可以获取包含方法调用的Expression&lt;Action&gt;,并从表达式树中解析出正在调用的MethodInfo。这将像这样使用:

ForResource<Order>().Performing(o => { o.AddItem(null); }).AllowUsersHaving(new Claim());

【讨论】:

  • for 1) 我可以使用“object”而不是“TParam1”吗?对于 2) 有什么方法可以在不指定 null 参数的情况下做到这一点?
  • +1。我真的想不出比你的第二个例子更通用的版本。
  • @Wili: 1) 不 - 代表不是协变的。 2) 没有。
  • 没有我想要的那么干净,但我很确定我想要的东西是不可能的。第二个例子非常接近,我决定使用它。
【解决方案2】:

如果您希望将动作委托方法的名称传递给 Performing 函数,这就是您要查找的内容。

public static IPermissionExp Performing<T>( 
    this IActionExp<T> exp, 
    Expression<Action<T, string, int>> action) 
{
    var expression = action.Body as MethodCallExpression;
    string actionMethodName = string.Empty;
    if (expression != null)
    {
        actionMethodName = expression.Method.Name;
    }
    // use actionMethodName ("AddItem" in the case below) here
}

这将允许您像这样调用方法...

ForResource<Order>().Performing((o, a, b) => o.AddItem(a, b)).AllowUsersHaving(new Claim()); 

【讨论】:

  • 当然,这需要调用者知道并声明参数。显然,不是你的第一偏好给你其他答案的 cmets :-(
【解决方案3】:

我最近在工作中做了一件事,您使用 lambda 定义了 a 方法,然后内部对象使用了该方法的名称。您也可以使用字符串,或者传入 MethodInfo,但第一个不是真正的类型安全(并且拼写错误是一个很大的风险),而后者不是很优雅。

基本上我有一个这样的方法(这不是确切的方法,它有点高级):

public void SetRequest(Request req, Expression<Func<Service, Func<long, IEnumerable<Stuff>>> methodSelector);

这里的关键是“表达式”,它可以让你“选择”这样的方法:

SetRequest(req, service => service.SomeMethodTakingLongReturningStuffs);

方法选择器被制作成一个表达式树,然后您可以从中获取不同的数据位。我不记得生成的树到底是什么样子的,它还取决于你的 lambdas 的外观。

【讨论】:

  • 我必须知道方法签名。如果我有不同签名的方法,我将不得不对遇到的每个签名使用不同的表达式。
  • 是的,您可以使用 Expression 或 Expression。
  • 我有 Permorming(这个 IActionExp exp, Func> 动作)。那不编译。
  • 我之前的评论有误,无法使用表达式。但是 Expression 可以。如果您查看我的示例,则需要将要制作成表达式树的委托的签名指定为 Expression 的类型参数。所以你需要有 Performing(this IActionExp exp, Expression action)... SLaks 的回答充分展示了你将如何去调用它。如果您不想指定方法的签名,我认为它不能比他的方式更“通用”和更漂亮。
  • 另一个“解决方案”是使用不同类型的参数指定大量的执行重载,这些参数将涵盖各种可能的方法签名。这不是很明智的实现,但它是一种替代方案。
【解决方案4】:

您可以将其作为 Action 传入,这不会强制任何返回类型。不过还是有点乱,因为你必须给方法传递一些参数才能编译。

【讨论】:

  • 行动会起作用,但我真的不在乎这些论点。我可以这样做:Func, Func>, Func>
猜你喜欢
  • 1970-01-01
  • 2012-01-03
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多