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

ご覧のとおり、必要なプロパティとメソッドを呼び出すために必要なすべての関連値を保持する 4 つのプロパティが含まれています。

そのコンストラクターでは、呼び出す必要があるプロパティまたはメソッドへのパスを最初のパラメーターとして渡すだけです。残りは、プロパティまたはメソッドが呼び出される型をインスタンス化するために必要になる可能性がある必須パラメーターです。コンストラクターはパス パラメーターを解析し、適切なインスタンスを提供します。

次に、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();
    }
}

プロパティとメソッドへのパスは、「+」記号を使用して 3 つの部分に分割されます。最初の部分は、使用するアセンブリの名前です。2 番目の部分は、インスタンス化する型の完全な名前です。3 番目の部分は、呼び出したいメソッドまたはプロパティの名前です。

また、各インスタンス変数はパスで指定されたタイプのインスタンスを保持し、上記のメソッドを呼び出すだけでそのプロパティを複数回変更できることにも注意してください。

編集: 内部プロパティ アクセスの例。

以下は、あなたが対処していると思われる状況です。

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

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

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

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

大学のクラスと学部のクラスがあるとします。Universityクラスで定義されたタイプのFacilityプロパティがあることがわかります。また、 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 に答える