繁体   English   中英

C# - 将可变数量的参数传递给方法中的其他方法

[英]C# - pass on variable amount of parameters to other method within a method

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

想象一下,您有一个具有 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# 中实现这一目标?

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

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

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

    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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM