代码之家  ›  专栏  ›  技术社区  ›  Carlo V. Dango

如何在C语言中定义高阶函数的参数名#

  •  3
  • Carlo V. Dango  · 技术社区  · 14 年前

    g 以函数作为参数。假设我想创建这样一个函数 f 如何为返回的增强方法定义参数名? 其动机是,我通常使用更高阶的方法,其中一些产生了新的方法。。这些可能很难使用,因为它们没有附加参数名等。

    举例说明如何 f型 分别可以在C中定义:

    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

    有什么建议吗?

    3 回复  |  直到 14 年前
        1
  •  2
  •   CodesInChaos    14 年前

    如果您只想要一个带有命名参数的固定委托类型,那么您可以定义自己的委托类型:

    Func的定义如下:

    public delegate TResult Func<in T, out TResult>(T arg)
    

    因此,可以使用所需的参数名定义自己的委托类型。

    但是在您的示例中,您希望保留传入的委托类型,因此在这里不起作用。理论上你可以这样定义你的函数:

    public static T Extend(T functionToWrap)
    {
    }
    

    不幸的是,没有好的泛型约束将输入类型限制为具有正确签名的委托(甚至根本就没有委托)。但是如果没有这些约束,实现将变得非常糟糕,并且您将失去如此多的静态类型安全性,以至于IMO不值得这样做。

    一种解决方法是:

    new MyFunc(Extend(f))
    

    或者您可以执行以下操作:

    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);
        }
    

    顺便说一下,甚至在.net 4之前,ConvertDelegate函数也可以用于获取委托的协/反方差。

        2
  •  1
  •   Dan Bryant    14 年前

    通过将新构造的委托动态绑定到基础Func delegate方法,可以强制转换为具有命名参数的委托:

    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();
        }
    }
    

        3
  •  0
  •   KeithS    14 年前

    这就是匿名代表的魅力所在;他们是匿名的。Func是一个方法的委托,它接受一个int并返回一个int。函数实际做什么,因此参数的名称,是不相关的。

    唯一可行的方法是,如果Calc是命名委托类型,定义的签名与CalcPriv相同。它仍然可以像写的那样工作,包括匿名扩展,但是你有一个Calc的命名参数。

    传递信息的另一种方法是使用 ///<summary></summary> 描述Calc参数的标记。

    最后,你可以从 Func<T,TResult> 创建 TakesPositiveInteger<T,TResult> 上课。这有点过分,但是如果你想谈谈自我文档化的代码。。。