通过将字符串传递给函数来访问属性或方法

时间:2013-09-20 05:29:02

标签: c# reflection dynamic-method

我有一个提供大量API的.net程序集,我需要为它编写一个COM包装器。由于时间限制,我无法为我的.net程序集提供每个方法和属性的接口。相反,我打算做的是编写一个通用的commandParser函数,它接受字符串参数给出被引用的属性或方法的完整路径(?),然后该方法必须调用正确的属性或方法。 例如,假设我需要设置属性Visible,我会传递如下的字符串(请参阅图像也用于类结构)或者如果需要调用方法

“APx.AcousticResponse.AcquiredWaveform.DeltaCursor.Visible”

“APx.BandpassLevel.FixedTuningFrequency.GetValue(单位)” **

显然我很无能,我知道使用反射是可能的,但我不在那里。这是我到目前为止一直没有取得任何成功的虚拟代码:P

public bool methodFromString(string methodName,object [] parameteres)
            {
                string [] split = methodName.Split(new char []{'.'});
                apx = new APx500();
                Type wrapType = apx .GetType();
                FieldInfo[] fields = wrapType.GetFields();
                MemberInfo[] members = wrapType.GetMembers();
                Console.WriteLine(members.Length);
                MethodInfo [] methods = wrapType.GetMethods();
                foreach (MemberInfo mem in members)
                {
                    //Console.WriteLine(mem.Name);
                    if(mem.Name == split[0])
                    {
                        Console.WriteLine(mem.Name);
                        Type memType = mem.GetType();
                        MethodInfo[] temp = memType.GetMethods();
                        foreach (MethodInfo t in temp)
                        {

                            Console.WriteLine(memType.Name);
                        }
                    }
                    //if (met.Name == methodName)
                    //{
                    //    try
                    //    {
                    //        met.Invoke(APx, parameteres);
                    //        break;
                    //    }
                    //    catch (TargetInvocationException ex)
                    //    {
                    //        Console.WriteLine(ex.Message);
                    //        Console.WriteLine(ex.InnerException);
                    //        break;
                    //    }
                    //}
                }


               // MethodInfo theMethod = wrapType.GetMethod(methodName);
                //theMethod.Invoke(APx, parameteres);
                //wrapType.InvokeMember(methodName,
                //    BindingFlags.InvokeMethod | BindingFlags.Public |
                //        BindingFlags.Static,
                //    null,
                //    null,
                //    parameteres);

                return true;
            }

非常感谢任何提示或帮助

1 个答案:

答案 0 :(得分:1)

以下代码可能有点长,但我确实认为它可以满足您的要求。

让我们从 DynamicInvoke 类开始。

public class DynamicInvoke
{
    List<object> Parameters { get; set; }
    List<string> Paths { get; set; }
    object Instance { get; set; }
    Type Type { get; set; }

    public DynamicInvoke(string path, params object[] parameters)
    {
        Parameters = parameters.ToList();

        Paths = path.Split('+').ToList();

        Type = AppDomain.CurrentDomain
                        .GetAssemblies()
                        .Where(x => x.GetName().Name == Paths[0])
                        .First()
                        .GetTypes()
                        .Where(x => x.FullName == Paths[1])
                        .First();

        Instance = Activator.CreateInstance(Type, Parameters.ToArray());
    }

    public T DynamicPropertyGet<T>()
    { 
        return (T)Type.GetProperty(Paths[2]).GetValue(Instance, null);            
    }

    public void DynamicPropertySet(object value)
    {
        Type.GetProperty(Paths[2]).SetValue(Instance, value, null);
    }

    public T DynamicMethodInvoke<T>(params object[] parameters)
    { 
        return (T)Type.GetMethods()
                      .Where(x => x.Name == Paths[2] && AreAllEqual(x, parameters))                          
                      .First()
                      .Invoke(Instance, parameters);
    }

    bool AreAllEqual(MethodInfo method, params object[] parameters)
    {
        var p1 = method.GetParameters().Select(x => x.ParameterType);
        var p2 = parameters.Select(x => x.GetType());

        var except1 = p1.Except(p2).ToList().Count;
        var except2 = p2.Except(p1).ToList().Count;

        return (except1 > 0 || except2 > 0) ? false : true;
    }
}

如您所见,它包含四个属性,这些属性将包含调用所需属性和方法所需的所有相关值。

在它的构造函数中,您只需将第一个参数作为属性的路径或您需要调用的方法传递。其余的是您可能需要实例化将调用属性或方法的类型所需的参数。然后构造函数将解析path参数并为您提供适当的实例。

然后,您可以调用 DynamicPropertyGet()方法从某个属性中获取值, DynamicPropertySet(object)方法来设置某个属性的值,或者 DynamicMethodInvoke(params object [])以调用方法。泛型参数用于指定将返回的实例的类型。

AreAllEqual(MethodInfo,params object [])方法只是决定调用哪个重载方法,具体取决于参数的数量和类型。

以下是我们的测试课程。您可以注意到它定义了属性和重载方法。

class People
{
    public string Name { get; set; }

    public People()
    {
        Name = "Billy";
    }

    public People(string name)
    {
        Name = name;
    }

    public string CallMe()
    {
        return Name;
    }

    public string CallMe(string value)
    {
        return value;
    }

    public void NoReturn()
    {
        Console.WriteLine("nothing");
    }
}

您现在可以使用以下代码行测试此方法。

class Program
{
    static void Main()
    {
        var path = "Types+Types.People+Name";
        var path2 = "Types+Types.People+CallMe";
        var path3 = "Types+Types.People+NoReturn";

        var instance1 = new DynamicInvoke(path);
        var instance2 = new DynamicInvoke(path, "Jill");
        var instance3 = new DynamicInvoke(path2);
        var instance4 = new DynamicInvoke(path2, "Johnny");
        var instance5 = new DynamicInvoke(path3);

        instance1.DynamicPropertySet("Tom");

        sc.WriteLine(instance1.DynamicPropertyGet<string>());
        sc.WriteLine(instance2.DynamicPropertyGet<string>());

        sc.WriteLine(instance3.DynamicMethodInvoke<string>());
        sc.WriteLine(instance4.DynamicMethodInvoke<string>("Timmy"));

        instance5.DynamicMethodInvoke<object>();

        Console.Read();
    }
}

使用“+”符号将属性和方法的路径分为三个部分。第一部分是您要使用的程序集的名称。第二部分是您要实例化的类型的全名。第三部分是您要调用的方法或属性的名称。

您还应该注意到每个实例变量都包含路径中指定的类型实例,您可以通过简单地调用上述方法多次修改其属性。

编辑:内部属性访问示例。

以下是您似乎正在处理的情况。

class University
{
    public Faculty Faculty { get; set; }

    public University()
    {
        Faculty = new Faculty();
    }
}

class Faculty
{
    public string Name { get; set; }

    public Faculty()
    {
        Name = "MIT";
    }
}

假设你有一个大学课程,并且你有一个 Faculty 课程。您可以看到大学类中定义的 Faculty 属性类型为 Faculty 。您还可以注意到 Faculty 类具有名称属性。此属性表示 double 类型的“ AnalyzeFilesFixe dSampleRate ”属性。

要访问此属性,您只需执行以下代码行。

var path = "Types+Types.University+Faculty";

var instance = new DynamicInvoke(path);

Consolec.WriteLine(instance.DynamicPropertyGet<Faculty>().Name);