我最近创建了这个扩展方法:
public static TR Calculate<TS, TR>(this TS item, Func<TS, TR> selector)
=> selector(item);
然后,我能够重构这个丑陋的代码,来自:
int value = panel.Controls.Cast<Control>().Last().Location.Y
+ panel.Controls.Cast<Control>().Last().Size.Height;
为:
int value = panel.Controls.Cast<Control>().Last().Calculate(
o => o.Location.Y + o.Size.Height);
我想知道是否有办法使用内置的.NET函数代替吗?
答案 0 :(得分:5)
通过“先天”,我猜你的意思是你自己不想要任何新方法?
嗯,你可以这样做:
value = ((Func<InputType, OutputType>)(o => o.First + o.Second + o.Property.Value))(collection[calc(param)]);
基本上,将lambda转换为委托类型,然后调用委托。
或者我可能过于复杂了。你实际想要的东西可能不会多次写collection[calc(param)]
。如果是这种情况,您可以:
var o = collection[calc(param)];
value = o.First + o.Second + o.Property.Value;
我不明白为什么你不能这样做。
我真的建议你为这种转换编写一个单独的方法。它会更具可读性。
// name this properly so that it describes what you actually want.
public OutputType TransformCollectionItem(TInput o) {
return o.First + o.Second + o.Property.Value;
}
答案 1 :(得分:5)
我要说你不应该这样做 - 我认为这不会让代码更具可读性。
鉴于原始代码:
int value = panel.Controls.Cast<Control>().Last().Location.Y
+ panel.Controls.Cast<Control>().Last().Size.Height;
您的扩展方法可以执行此操作:
int value = panel.Controls.Cast<Control>().Last().Calculate(
o => o.Location.Y + o.Size.Height);
但这样做似乎没有什么优势:
var c = panel.Controls.Cast<Control>().Last();
int value = c.Location.Y + c.Size.Height;
后者实际上更短,并且不要求读者了解扩展方法。
此外,您的扩展方法将显示在一切工具提示中......
请注意,它确实允许一些有趣的代码,例如
double negated = 1.0.Calculate(x => -x);
答案 2 :(得分:4)
您在此处描述的操作通常称为“apply”,因为它只是将函数应用于参数作为扩展方法。你想要一种“天生地”做到这一点的方法;我不太清楚你的意思。 功能应用程序已经内置于C#的语法中。要将函数F
应用于参数a
以在C#中获得结果r
,您可以这样做:
r = F(a)
因此,在您的情况下,您将lambda分配给变量然后应用它,或者,如同其他答案注释,将其转换为适当的函数类型并应用它。
如果你想将函数应用程序作为一个带lambda的扩展方法,你必须自己编写它。
你在这里有效地提到的是C#中缺少“let expressions”。我真正想写的是:
int value =
let o = panel.Controls.Cast<Control>().Last() in
o.Location.Y + o.Size.Height;
支持哪种语言,但C#仅支持查询理解。
请参阅我对这个问题的回答,了解更多关于C#中的“let expressions”及其有用的原因,以及它们与您的应用程序函数的对应关系:DRY (Don't Repeat Yourself) and if assignements
顺便提一下,如果你为方法Select
命名并创建一个名为SelectMany
的双应用程序版本,那么你可以使用LINQ ......好吧,任何东西:
using System;
static class X
{
public static R Select<A, R>(this A item, Func<A, R> selector) =>
selector(item);
public static R SelectMany<A, B, R>(this A item, Func<A, B> toB, Func<A, B, R> toR) =>
toR(item, toB(item));
}
public class P
{
public static void Main()
{
string myString = "hello";
string result = from s in myString
from b in s + "goodbye"
select b.ToUpper() + " " + s;
Console.WriteLine(result);
}
}
这是编写简单程序的一种奇怪的巴洛克式方式,但是如果你真的倾向于使用已经使用该语言的东西来制作扩展方法,那么你就可以做到!
练习:实施身份monad 。你很顺利!