通过反射调用带有类参数的方法

本文关键字:参数 方法 反射 调用 | 更新日期: 2023-09-27 18:19:03

我刚刚开始使用c#反射,我遇到了调用以内部类作为参数的方法的问题:

样本类:

public class MyClass 
{
    public class CustomColor 
    {
        public int h;
        public int s;
        public int v;
    }
    public string[] ConvertColors(List<CustomColor> colors)
    {
        //...
    }
}

我用来调用这个类中其他方法的代码:

FieldInfo info = cInstanceContainerObject.GetType().GetField("_myClass", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
dynamic myClassObject = info.GetValue(cInstanceContainerObject);

允许我这样做:

myClassObject.SomeSampleMethod(int sampleParam);

然而,我一直在弄清楚如何为上面的ConvertColors方法创建适当的参数。(

通过反射调用带有类参数的方法

我不知道你是如何创建你的cInstanceContainerObject的。我用的是MethodInfo.Invoke。下面是代码:

//Your class
public class MyClass 
{
    public class CustomColor 
    {
        public int h;
        public int s;
        public int v;
    }
    public string[] ConvertColors(List<CustomColor> colors)
    {
        return new string[]{"1"};
    }
}
//Usage
MyClass mc = new MyClass();
    MyClass.CustomColor cc = new MyClass.CustomColor();
    Type t = mc.GetType();
    MethodInfo mi = t.GetMethod("ConvertColors");
    List<MyClass.CustomColor> lst = new List<MyClass.CustomColor>
    {   
        new MyClass.CustomColor(),
        new MyClass.CustomColor()
    };
    var x = (string[])mi.Invoke(mc,new object[]{lst});
    Console.WriteLine (x.Count());

Tom,

尝试传递要转换的颜色作为引用。

在下面的例子中,作为引用传入的颜色(CustomColor)将被更新,而不是返回字符串。

所以,不像这样调用方法:
string[] colors = ConvertColors(yourColorList, foo, bar);

它可以被称为:

ConvertColors(yourColorList, foo, bar);

的例子:

public class MyClass
{
    public class CustomColor
    {
        public int h;
        public int s;
        public int v;
    }
    public enum Convert { H, S, V, HS, HV, SV, HSV };
    public void ConvertColors(ref List<CustomColor> colors, Convert type,
        ref CustomColor changeAmt)
    {
        // Variables to change H, S, and V from changeAmt parameter:
        int changeH = changeAmt.h;
        int changeS = changeAmt.s;
        int changeV = changeAmt.v;
        // Change the actual colors which were passed as 'colors' parameter.
        switch (type)
        {
            // Change H.
            case Convert.H:
                foreach (CustomColor c in colors)
                    c.h += changeH;
                break;
            // Change S.
            case Convert.S:
                foreach (CustomColor c in colors)
                    c.s += changeS;
                break;
            // Change V.
            case Convert.V:
                foreach (CustomColor c in colors)
                    c.v += changeV;
                break;
            // Change HS.
            case Convert.HS:
                foreach (CustomColor c in colors)
                {
                    c.h += changeH;
                    c.s += changeS;
                }
                break;
            // Change HV.
            case Convert.HV:
                foreach (CustomColor c in colors)
                {
                    c.h += changeH;
                    c.v += changeV;
                }
                break;
            // Change SV.
            case Convert.SV:
                foreach (CustomColor c in colors)
                {
                    c.s += changeS;
                    c.v += changeV;
                }
                break;
            // Change HSV.
            case Convert.HSV:
                foreach (CustomColor c in colors)
                {
                    c.h += changeH;
                    c.s += changeS;
                    c.v += changeV;
                }
                break;
        }
    }
}

解释:

'enum'允许你为你的方法创建一个自定义参数:

public enum Convert { H, S, V, HS, HV, SV, HSV };

'switch'语句允许你处理这些参数:

switch (type)
        {
            case Convert.H:
                // Do something
                return;
            case Convert.S:
                // Do something
                return;
            case Convert.V:
                // Do something
                return;

创建一个您想要做的更改的实例作为一个新的CustomColor,并传递一个对CustomColors列表的引用,您的自定义参数,以及一个对更改的引用作为CustomColor:

private void AnyMethod()
    {
        // Create first custom color.
        CustomColor color1 = new CustomColor();
        color1.h = 50;
        color1.s = 25;
        color1.v = 35;
        // Create second custom color.
        CustomColor color2 = new CustomColor();
        color2.h = 50;
        color2.s = 25;
        color2.v = 35;
        // Create third custom color.
        CustomColor color3 = new CustomColor();
        color3.h = 50;
        color3.s = 25;
        color3.v = 35;
        // Add to list of custom colors.
        List<CustomColor> colorList = new List<CustomColor>();
        colorList.Add(color1);
        colorList.Add(color2);
        colorList.Add(color3);
        // Create changes as a new color.
        CustomColor colorChange = new CustomColor();
        colorChange.h = -10;
        colorChange.s = 47;
        colorChange.v = -15;
        // Update all colors in your list.
        ConvertColors(ref colorList, Convert.HSV, ref colorChange); // BOOM.
    }

如果您希望获得后面的字符串:

string[] hsvStrings =
        {
            color1.h.ToString(),
            color1.s.ToString(),
            color1.v.ToString(),
            // Continue...
        };

经过一个不眠之夜,我终于想出了如何实现这一目标。两个答案都帮助我看到了导致我得到答案的可能性,但是我必须在不引用外部DLL或对其进行任何修改的情况下实现这一点,只是通过反射获得它的主对象的实例,然后调用其中的各种方法(其中一些需要的类仅由DLL本身提供,正如您可以在我的示例中看到的)。

我的解决方案是这样的(请随意提供更好的替代方案):

通过使用方法参数

获取List和CustomColor各自的Type:
Type listType = myClassObject.GetType()
                             .GetMethod("ConvertColors")
                             .GetParameters()[0]
                             .ParameterType;
Type colorType = myClassObject.GetType()
                 .GetMethod("ConvertColors")
                 .GetParameters()[0]
                 .ParameterType
                 .GetProperty("Item")
                 .PropertyType;

然后使用Activator:

创建整个列表和单个CustomColors的单独实例
dynamic colorList = Activator.CreateInstance(listType);
dynamic customColor = Activator.CreateInstance(colorType);
colorList.Add(customColor);
myClassObject.ConvertColors(colorList); //works!