【问题标题】:C# - pass on variable amount of parameters to other method within a methodC# - 将可变数量的参数传递给方法中的其他方法
【发布时间】:2020-05-31 14:39:14
【问题描述】:

我知道标题有点难以理解,但下面的例子应该能阐明我的意思:

假设您有一个包含 2 个重载的方法:

void Method(int i)
{
    Console.WriteLine("Method(int) called");
}

void Method(int i, string s)
{
    Console.WriteLine("Method(int, string) called");
}

那么你有另一种方法,它采用可变数量的参数:

void MethodOverload(params dynamic[] parameters)
{
    Method(parameters); // Call one of the overloading methods depending on the parameter amount and their type 
}

上面的方法接受任意数量的任意类型的参数。我想根据传递的参数数量及其类型调用其中一种重载方法。

例如:

void Run()
{
    TestFuncOverload(5);                 // Output: "testFunc(int) called"
    TestFuncOverload(5, "some text");    // Output: "testFunc(int, string) called"

    TestFuncOverload(5, 5);              //Error
}

如何在 C# 中实现这一点?

【问题讨论】:

  • if (parameters.Length == 1 && parameters[0] is int) Method(parameters[0]); if (parameters.Length == 2 && parameters[0] is int && parameters[1] is string) Method(parameters[0], parameters[1]); 怎么样,我没有看到其他解决方案。
  • 嗯,是的,但这是一个简化的示例。每次我在代码中需要这样的东西时,我不想为所有类型的参数和每个函数的所有重载数量创建几十个 if 语句。

标签: c# variables dynamic parameters overloading


【解决方案1】:

你可以用reflection 来做,但我不推荐它。反射很慢,要做到这一点,您需要大量使用它。您应该尝试用不同的方法来解决它,但如果您真的需要这样做,这应该可以解决问题:

    public void MethodOverload(params dynamic[] parameters)
    {
        //Check if the array is null
        if (parameters == null)
            throw new ArgumentNullException(nameof(parameters));

        //Create a list of the types in the dynamic[]
        var inputParameterTypes = new Type[parameters.Length];
        for (int i = 0; i < parameters.Length; i++)
        {
            inputParameterTypes[i] = parameters[i].GetType();
        }

        const string NameOfMethod = nameof(Method); //This should be the name of your method which will be called

        //Get every method from this class which has the name you are looking for
        var methods = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(x => x.Name == NameOfMethod);

        foreach (var method in methods)
        {
            //Get the parameters of the method
            var methodParameters = method.GetParameters();

            if (methodParameters.Length != inputParameterTypes.Length)
                continue;

            //Check if the types match with the input parameters
            var match = true;
            for (int i = 0; i < methodParameters.Length; i++)
            {
                //Check if the type matches
                if (methodParameters[i].ParameterType == inputParameterTypes[i])
                    continue;

                //Doesn't match
                match = false;
            }
            if (!match)
                continue;

            //Call the method and return
            method.Invoke(this, parameters);
            return;
        }


        //If this is reached no valid methods were found
        throw new Exception("No valid methods found!");
    }

(此代码假定所有方法都在同一个类中)

使用此代码进行一些测量后:

        var a = new Foo();

        var parameters = new dynamic[][] 
            { 
                new dynamic[] { 1, "Test" }, 
                new dynamic[] { 2 } 
            };

        var sw = Stopwatch.StartNew();
        for (int i = 0; i < Num; i++)
        {
            a.MethodOverload(parameters[i % 2]);
        }
        sw.Stop();
        Console.WriteLine($"{Num} iterations took {sw.Elapsed.TotalMilliseconds} milliseconds. Average time: {sw.Elapsed.TotalMilliseconds / Num} milliseconds");

(从被调用函数中删除了 Console.WriteLine)

结果如下:

10000000 iterations took 5283.9398 milliseconds. Average time: 0.00052839398 milliseconds
100000000 iterations took 51244.9142 milliseconds. Average time: 0.000512449142 milliseconds

【讨论】:

    【解决方案2】:

    我可以用下面的代码做到这一点。这需要大量的反思,您可以考虑另一种方法来避免性能问题。

    public class Test
    {
        private void Method(int i)
        {
            Console.WriteLine("Method(int) called");
        }
        private void Method(int i, string s)
        {
            Console.WriteLine("Method(int, string) called");
        }
        public void Method(params object[] parameters)
        {
            var m = typeof(Test).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
                                    .Where(x => x.Name == "Method" &&
                                               !x.GetParameters()
                                                 .Any(p => p.IsDefined(typeof(ParamArrayAttribute), false)))
                                    .Where(x => x.GetParameters().Count() == parameters.Count())
                                    .Where(x => x.GetParameters()
                                                 .Select(y => Type.GetType("System." + y.ParameterType.Name))
                                                 .Zip(parameters.Select(z => z.GetType()), Equals)
                                                 .All(q => q))
                                    .FirstOrDefault();
    
            if(m == null) throw new Exception ("method not found");
    
            //null result because of void method.
            var result = m.Invoke(this, parameters);
        }
    }
    
    static void Main(string[] args)
    {
          Test t = new Test();
          //"Method(int) called"
          t.Method(0);
          //"Method(int, string) called"
          t.Method(0, "");
          //throws ex 
          t.Method("", "");
    }
    

    【讨论】:

      【解决方案3】:

      您需要使用Reflection 并通过Invoke 调用该方法。

      【讨论】:

        猜你喜欢
        • 2015-10-01
        • 1970-01-01
        • 2016-05-08
        • 1970-01-01
        • 2013-01-29
        • 2018-07-06
        • 1970-01-01
        • 2016-12-31
        • 1970-01-01
        相关资源
        最近更新 更多