C# 标签目标接收值意味着什么?
关于C# 标签目标接收值意味着什么?,c#,.net,linq,expression-trees,linq-expressions,C#,.net,Linq,Expression Trees,Linq Expressions,关于System.Linq.Expressions.LabelExpression及其辅助类和方法,我有几个问题 1) 标签表达式类的文档如下所示: 表示可以放在任何表达式上下文中的标签。如果跳转到,它将获得相应的GotoExpression提供的值。否则,它将接收DefaultValue中的值。如果类型等于System.Void,则不应提供任何值 向标签目标返回值意味着什么?换句话说,标签目标接收值意味着什么?我一生中从未这样做过——当我跳转到标签目标时,将值传递给它 2) 虽然前往标签目标完
System.Linq.Expressions.LabelExpression
及其辅助类和方法,我有几个问题
1) 标签表达式类的文档如下所示:
表示可以放在任何表达式上下文中的标签。如果跳转到,它将获得相应的GotoExpression
提供的值。否则,它将接收DefaultValue
中的值。如果类型
等于System.Void
,则不应提供任何值
向标签目标返回值意味着什么?换句话说,标签目标接收值意味着什么?我一生中从未这样做过——当我跳转到标签目标时,将值传递给它
2) 虽然前往标签目标完全有道理,但返回并继续前往标签目标意味着什么
标签值的目的似乎是提供返回值。如果您查看下面的示例代码,“payload”的返回值被传递到“target”标签,并成为表达式的返回代码。我尝试了Expression.Return和Expression.Break,结果都一样。表达式.Continue没有向标签传递值的重载
var target = Expression.Label(typeof(string));
var debugPrint = typeof(Debug).GetMethod("Print", new Type[] { typeof(string) });
var expr = Expression.Block(typeof(string),
new Expression[] {
Expression.Call(debugPrint,Expression.Constant("Before")),
Expression.Return(target,Expression.Constant("payload"),typeof(string)),
//Expression.Break(target,Expression.Constant("payload")),
Expression.Call(debugPrint,Expression.Constant("During")),
Expression.Label(target,Expression.Constant("Default")),
}
);
var result = Expression.Lambda<Func<string>>(expr).Compile()();
解决第二个问题:您总是“转到”标签目标。“返回”、“继续”和“中断”是您如何“到达”目标的风格。Return意味着标签目标位于方法的末尾,并向其传递返回值。Continue和Break表示标签目标正在参与一个循环。有时,将Linq表达式视为一种在类似于C但不完全是C的东西中构建代码的方法是很有帮助的。这是其中一次 下面的代码是使用表达式实现a
Math.Max(inta,intb)
。对于return
语句,没有像C#中那样的快捷方式。您必须创建标签
// (a, b =>
// {
// if(a > b)
// return a;
// else
// return b;
// }
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var returnLabel = Expression.Label(typeof (int));
Expression<Func<int, int, int>> returnMax = (Expression<Func<int, int, int>>)Expression.Lambda
(
Expression.Block
(
Expression.IfThenElse
(
Expression.GreaterThan(a, b),
Expression.Return(returnLabel, a),
Expression.Return(returnLabel, b)
),
Expression.Label(returnLabel, Expression.Constant(0))
),
a,
b
);
var shouldBeSix = returnMax.Compile()(5, 6);
。。。因此需要一个默认值
由于LabelExpression
必须有一个类型和一个值,因此默认值的类型、LabelTarget
和GotoExpression
都必须匹配。原始示例代码使用0作为默认值,但正如您所看到的,这将永远不会被使用。如果将0
切换为0.0
或null
,则在调用.Compile()
时表达式将失败
2) 从示例代码中可以看出,如果不使用标签目标,就无法从函数中“返回”。正如@Grax所暗示的,
Expression.Goto
,Expression.Continue
,Expression.Break
,Expression.Return
所有返回的GotoExpressions
功能几乎相同。肯定更好;谢谢我自己对此很好奇。似乎Return、Continue和Break都返回基本相同的GotoExpression,不同的是.Kind属性。此属性被描述为“仅供参考”,谢谢@Grax。我想我们应该互相同情。这令人困惑。您正在描述一个名为GotoExpressionKind
的信息属性,它是一个枚举,仅供参考。然而,我问的是两件事的含义:(1)你如何回到、继续或打破标签目标?以及(2)标签如何接收值?多么漂亮的解释!我也喜欢@Grax的答案,但我不得不告诉你们,语言和结构的清晰程度令人震惊。你的回答在我脑海中打开了钥匙。不过,只有一件事:文档一点也不多,您是如何知道这一切的?你知道如果你告诉我,你会教人钓鱼等等。有一次,我参与了一个项目,我们研究了如何广泛使用表达式。有很多尝试和错误。如果你想要一个有趣的、受虐狂式的挑战:没有内置的捷径来创建for循环(Expression.loop
本质上是一个while循环)。尝试构建一个。我还发现这个博客系列的前几篇文章很有帮助:谢谢,@Shlomo。在过去一年左右的时间里,我浏览了任性博客上的帖子。我将很快编写代码,用于编写和访问System.Linq.expressions
命名空间中所有73个表达式家族(我一直在计算和分类)。:-)
// (a, b =>
// {
// if(a > b)
// return a;
// else
// return b;
// }
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
var returnLabel = Expression.Label(typeof (int));
Expression<Func<int, int, int>> returnMax = (Expression<Func<int, int, int>>)Expression.Lambda
(
Expression.Block
(
Expression.IfThenElse
(
Expression.GreaterThan(a, b),
Expression.Return(returnLabel, a),
Expression.Return(returnLabel, b)
),
Expression.Label(returnLabel, Expression.Constant(0))
),
a,
b
);
var shouldBeSix = returnMax.Compile()(5, 6);
var returnLabel = Expression.Label(typeof (int));
Expression<Func<int>> returnsSix = (Expression<Func<int>>)Expression.Lambda
(
Expression.Label(
returnLabel,
Expression.Constant(6)
)
);
var alsoSix = returnsSix.Compile()();