Доступ к свойству или методу путем передачи строки в функцию

У меня есть сборка.net, предоставляющая огромное количество API, и мне нужно написать для нее оболочку 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;
            }

Любые советы или помощь высоко ценится

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

Пути к свойствам и методам разделены на три части с помощью знака "+". Первая часть - это название сборки, которую вы хотите использовать. 2-я часть - полное имя типа, который вы создадите. Третья часть - это имя метода или свойства, которое вы хотите вызвать.

Вы также должны заметить, что каждая переменная экземпляра содержит экземпляр вашего типа, указанный в пути, и вы можете изменять его свойства несколько раз, просто вызывая вышеупомянутые методы.

РЕДАКТИРОВАТЬ: Пример доступа к внутренней собственности.

Ниже приведена ситуация, с которой вы, похоже, имеете дело.

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 есть свойство Name. Это свойство представляет ваше свойство "AnalyzeFilesFixe‌ dSampleRate" типа double.

Чтобы получить это свойство, вам просто нужно выполнить следующие строки кода.

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

var instance = new DynamicInvoke(path);

Consolec.WriteLine(instance.DynamicPropertyGet<Faculty>().Name);
Другие вопросы по тегам