Доступ к свойству или методу путем передачи строки в функцию
У меня есть сборка.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);