如何在C#中为高阶函数定义参数名称#
在C#中,可以创建更高阶的函数,即。函数g
将函数作为参数。假设我想创建一个给定函数f
的函数,并返回扩展其功能的另一个函数。 如何为返回的增强方法定义参数名称?的动机是,我正在使用更高阶的方法,其中一些产生新的方法..这些可能很难使用,因为没有参数名称等附加到他们。如何在C#中为高阶函数定义参数名称#
示出了如何g
f
和分别可在C#中定义的一个例子:
我定义的方法扩展可以EXTENS方法采取T
作为参数并返回一个S
。
static class M
{
public static Func< T, S> Extend(Func< T, S> functionToWrap)
{
return (someT) =>
{
...
var result = functionToWrap(someT);
...
return result;
};
}
}
然后我们可以在不改变方法的情况下在我们的类上扩展一个方法。
class Calc2
{
public Func< int, int> Calc;
public Calc2()
{
Calc = M.Extend< int, int>(CalcPriv);
}
private int CalcPriv(int positiveNumber)
{
if(positiveNumber < 0) throw new Exception(...);
Console.WriteLine("calc " + i);
return i++;
}
}
唉,参数名称positiveNumber
不再可用,因为唯一可用的信息是Func<int, int> Calc
。那是当我通过输入new Calc2().Calc(-1)
来使用扩展方法时,我从IDE中得不到任何帮助,实际上我的论点是错误的。
如果我们可以定义一个delegate
并将其转换为此值将会很好,但这是不可能的。
有什么建议吗?
如果你只是想用命名的参数固定的委托类型,然后你可以定义自己的委托类型:
Func键仅仅是这样定义的:
public delegate TResult Func<in T, out TResult>(T arg)
所以,你可以定义你想要的参数名称自己的委托类型。
但在你的例子中,你想保留传入的委托类型,所以这在这里不起作用。从理论上讲,你可以定义你的函数是这样的:
public static T Extend(T functionToWrap)
{
}
不幸的是,制约与正确的签名(或甚至只是代表的话)的输入型的代表没有很好的通用约束。但是如果没有这些限制,实施会变得如此丑陋,而且你会失去太多的静态类型安全,以至于IMO不值得。
一种解决方法是使用:
new MyFunc(Extend(f))
其中MYFUNC定义你想要的parameternames。
或者你可以做到以下几点:
public static T ConvertDelegate<T>(Delegate d)
{
if (!(typeof(T).IsSubclassOf(typeof(Delegate))))
throw new ArgumentException("T is no Delegate");
if (d == null)
throw new ArgumentNullException();
MulticastDelegate md = d as MulticastDelegate;
Delegate[] invList = null;
int invCount = 1;
if (md != null)
invList = md.GetInvocationList();
if (invList != null)
invCount = invList.Length;
if (invCount == 1)
{
return (T)(object)Delegate.CreateDelegate(typeof(T), d.Target, d.Method);
}
else
{
for (int i = 0; i < invList.Length; i++)
{
invList[i] = (Delegate)(object)ConvertDelegate<T>(invList[i]);
}
return (T)(object)MulticastDelegate.Combine(invList);
}
}
public static TDelegate Extend<TDelegate,TArg,TResult>(Func<TArg,TResult> functionToWrap)
where TDelegate:class
{
Func<TArg,TResult> wrappedFunc= DoTheWrapping(functionToWrap);
return ConvertDelegate<TDelegate>(wrappedFunc);
}
BTW的ConvertDelegate功能,可用于获取有关代表合作/逆变甚至之前,.NET 4
+1,我没有意识到你可以像这样构造一个参数匹配的委托。 – 2010-10-28 22:10:19
我更喜欢调用者构造所需类型的新委托的解决方法。它仍然很短,易于阅读和类型安全。 – CodesInChaos 2010-10-28 22:18:35
这就是匿名代表的美丽;他们是匿名的。 Func是一个接受int并返回int的方法的委托。函数实际做了什么,因此参数的名称是无关紧要的。
这将工作的唯一方法是如果Calc是一个命名的委托类型,定义与签名相同的CalcPriv。它仍然可以按照书面形式工作,包括匿名扩展,但是您将拥有Calc的命名参数。
传递信息的另一种方式是使用描述Calc参数的///<summary></summary>
标签的xml-doc Calc。
最后,你可以从Func<T,TResult>
派生出来创建一个TakesPositiveInteger<T,TResult>
类。这是走的太远了一点,但如果你想谈谈自记录代码...
将代码更改为'public delegate int Calc(int someArg); public Calc CalcM; public Calc2() { CalcM =(Calc)M.Extend
有可能转换为用命名参数委托,通过一个新构造的代表动态结合到下面的函数功能委托方法:
public delegate double CalcFunc(double value);
static class M
{
public static Func<T, S> Extend<T,S>(Func<T, S> functionToWrap)
{
return (someT) => functionToWrap(someT);
}
}
class Program
{
private static double Calc(double input)
{
return 2*input;
}
[STAThread]
static void Main()
{
Func<double, double> extended = M.Extend<double, double>(Calc);
CalcFunc casted = (CalcFunc)Delegate.CreateDelegate(typeof(CalcFunc), extended.Target, extended.Method);
Console.WriteLine(casted(2) + " == 4");
Console.WriteLine("I didn't crash!");
Console.ReadKey();
}
}
警告一句话:这不会对剧组进行任何编译时检查。如果签名不完全匹配,您将在运行时遇到绑定失败(除了特别支持.NET 4中的变换)。
哇,太好了,也许Extend方法也应该把委托类型作为参数,所以它可能是执行Delegate.CreateDelegate(typeof(...))的那个) – 2010-10-28 21:59:26
如果extended是一个多播委托,这是否正确工作?但是由于Extend对多播委托无用,所以在这种情况下check +异常应该足够了。如果所需的委托类型在创建代码时已知,那么您可以简单地使用新的CalFunc(扩展)。 – CodesInChaos 2010-10-28 22:09:24
@Carlo,请参阅CodeInChaos的解决方案;委托构造函数更干净,更安全。 – 2010-10-28 22:11:02
你需要知道参数名称?您在何处/如何在您发布的代码中使用它? – sepp2k 2010-10-28 21:15:03
有没有这样做是不同的,只是创建一个继承M和重写Extend的类? – 2010-10-28 21:23:19
以上是一个例子,而不是问题。问题是关于能够使用记录参数输入的更高阶方法创建方法 – 2010-10-28 21:25:56