1

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

“APx.AcousticResponse.AcquiredWaveform.DeltaCursor.Visible”

或者

“APx.BandpassLevel.FixedTuningFrequency.GetValue(Unit)”**

显然我一无所知,我知道使用反射是可能的,但我还没有到那里。这是我迄今为止一直在工作的虚拟代码,但没有任何成功: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;
            }

非常感谢任何提示或帮助

4

1 回答 1

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

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

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

然后,您可以调用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";
    }
}

假设您有一个大学课程,并且您有一个教师课程。您可以看到在University类中定义了Faculty类型的Faculty属性。您还可以注意到,Faculty类有一个Name属性。此属性代表您的double类型的“ AnalyzeFilesFixe‌​dSampleRate ”属性。

要获得此属性,您只需执行以下代码行。

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

var instance = new DynamicInvoke(path);

Consolec.WriteLine(instance.DynamicPropertyGet<Faculty>().Name);
于 2013-09-20T22:37:49.267 回答