我有一个提供大量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;
}
非常感谢任何提示或帮助
答案 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);