C#:使用反射按名称获取 field/property/method 值(字符串或 uint)
C#: Get field/property/method value (which is either string or uint) by name using reflection
我正在尝试从一个有 5 年历史的开源项目的许多旧程序集中解析一些数据,并且大部分都可以正常工作,但代码非常冗长。
编辑:另外,我被 .Net Framework 3.5 困住了
有两个成员我感兴趣,他们的名字是 "Version"
和 "TargetVersion"
。
直到最近,"Version"
成员还是 string
以各种方式定义的。它现在被替换为 "ModVersion"
从程序集版本中获取的成员。一些例子:
public string Version => "1.4";
public static readonly string Version = "1.8.14";
public const string Version = "2.8";
public static Version ModVersion => typeof(MainClass).Assembly.GetName().Version;
TargetVersion
成员只有两种形式:public static readonly uint
或public const uint
。
所以目前我得到了成员类型,然后为各种成员类型嵌套了 if .. else if ...
,如下所示:
string dirty = string.Empty;
MemberTypes memberType = GetMemberType(mod, "Version");
if (memberType == MemberTypes.Property) {
Log.Info("It's a property");
dirty = mod
.GetProperty("Version", PUBLIC_STATIC)
.GetValue(mod, null)
.ToString();
} else if (memberType == MemberTypes.Field) {
Log.Info("It's a field");
dirty = mod
.GetField("Version", PUBLIC_STATIC)
.GetValue(mod)
.ToString();
} else if (memberType == MemberTypes.Method) {
Log.Info("It's a method");
dirty = mod
.GetMethod("Version", PUBLIC_STATIC)
.Invoke(null, null)
.ToString();
} else {
Log.Info("Version: Unsupported member type or not found");
}
然后我有一堆类似的代码来获取 "TargetVersion"
,这是一个 uint
。现在我需要添加一些其他东西来获得新的 "ModVersion"
以防找不到 "Version"
...
有什么方法可以减少重复?例如,是否可以使用泛型? (我还是 C# 的新手)以避免重复 string
vs uint
vs. Version
的代码?有没有办法减少处理不同成员类型的代码量?
我在 SO 的其他地方看到过类似的东西,但不知道如何使其适应我的用例:
MemberInfo info = type.GetField(memberName) as MemberInfo ??
type.GetProperty(memberName) as MemberInfo;
我最终希望实现的是我可以指定类型和成员名称并只取回值。有点像 bool TryGetMemberValue<T>(Type thing, string memberName, out <T>value)
方法。
希望这个问题不会太蠢,我还在学习基础知识:o
你快到了,也许是这样的
注意 : 我刚刚返回了一个字符串。如果你愿意,你可以传递另一个通用参数并转换结果,但是我假设你想要使用的所有类型都会覆盖 ToString
public static bool TryGetValue<T>(T instance, string name, out string value)
{
value = default;
var member = typeof(T).GetMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.FirstOrDefault();
if (member == null)return false;
switch (member.MemberType)
{
case MemberTypes.Field:
value = (member as FieldInfo)?.GetValue(instance).ToString();
break;
case MemberTypes.Method:
value = (member as MethodInfo)?.Invoke(instance, null).ToString();
break;
case MemberTypes.Property:
value = (member as PropertyInfo)?.GetValue(instance).ToString();
break;
default:
return false;
}
return true;
}
或者如果你真的想要 type 显式
public static bool TryGetValue<T,T2>(T instance, string name, out string value)
{
...
switch (member.MemberType)
{
case MemberTypes.Field:
value = (T2)(member as FieldInfo)?.GetValue(instance);
...
}
更新
这是一个你给出类型的版本,它启动一个实例来获取实例成员,然后在需要时进行处理
public static T GetValue<T>(object instance , MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Field: return (T)(member as FieldInfo)?.GetValue(instance);
case MemberTypes.Method: return (T)(member as MethodInfo)?.Invoke(instance, null);
case MemberTypes.Property: return (T)(member as PropertyInfo)?.GetValue(instance);
default:return default;
}
}
public static bool TryGetValue<T>(Assembly asm, string className, string name, out T value)
{
value = default;
var type = asm.GetType(className);
var instance = Activator.CreateInstance(type);
try
{
var member = type.GetMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.FirstOrDefault();
if (instance == null || member == null) return false;
value = GetValue<T>(instance, member);
}
finally
{
(instance as IDisposable)?.Dispose();
}
return true;
}
用法
Assembly asm = <some assembly>;
if(TryGetValue<uint>(asm, "MyNameSpace.Test1", "TargetVersion", out var out1))
Console.WriteLine(out1);
我正在尝试从一个有 5 年历史的开源项目的许多旧程序集中解析一些数据,并且大部分都可以正常工作,但代码非常冗长。
编辑:另外,我被 .Net Framework 3.5 困住了
有两个成员我感兴趣,他们的名字是 "Version"
和 "TargetVersion"
。
直到最近,"Version"
成员还是 string
以各种方式定义的。它现在被替换为 "ModVersion"
从程序集版本中获取的成员。一些例子:
public string Version => "1.4";
public static readonly string Version = "1.8.14";
public const string Version = "2.8";
public static Version ModVersion => typeof(MainClass).Assembly.GetName().Version;
TargetVersion
成员只有两种形式:public static readonly uint
或public const uint
。
所以目前我得到了成员类型,然后为各种成员类型嵌套了 if .. else if ...
,如下所示:
string dirty = string.Empty;
MemberTypes memberType = GetMemberType(mod, "Version");
if (memberType == MemberTypes.Property) {
Log.Info("It's a property");
dirty = mod
.GetProperty("Version", PUBLIC_STATIC)
.GetValue(mod, null)
.ToString();
} else if (memberType == MemberTypes.Field) {
Log.Info("It's a field");
dirty = mod
.GetField("Version", PUBLIC_STATIC)
.GetValue(mod)
.ToString();
} else if (memberType == MemberTypes.Method) {
Log.Info("It's a method");
dirty = mod
.GetMethod("Version", PUBLIC_STATIC)
.Invoke(null, null)
.ToString();
} else {
Log.Info("Version: Unsupported member type or not found");
}
然后我有一堆类似的代码来获取 "TargetVersion"
,这是一个 uint
。现在我需要添加一些其他东西来获得新的 "ModVersion"
以防找不到 "Version"
...
有什么方法可以减少重复?例如,是否可以使用泛型? (我还是 C# 的新手)以避免重复 string
vs uint
vs. Version
的代码?有没有办法减少处理不同成员类型的代码量?
我在 SO 的其他地方看到过类似的东西,但不知道如何使其适应我的用例:
MemberInfo info = type.GetField(memberName) as MemberInfo ??
type.GetProperty(memberName) as MemberInfo;
我最终希望实现的是我可以指定类型和成员名称并只取回值。有点像 bool TryGetMemberValue<T>(Type thing, string memberName, out <T>value)
方法。
希望这个问题不会太蠢,我还在学习基础知识:o
你快到了,也许是这样的
注意 : 我刚刚返回了一个字符串。如果你愿意,你可以传递另一个通用参数并转换结果,但是我假设你想要使用的所有类型都会覆盖 ToString
public static bool TryGetValue<T>(T instance, string name, out string value)
{
value = default;
var member = typeof(T).GetMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.FirstOrDefault();
if (member == null)return false;
switch (member.MemberType)
{
case MemberTypes.Field:
value = (member as FieldInfo)?.GetValue(instance).ToString();
break;
case MemberTypes.Method:
value = (member as MethodInfo)?.Invoke(instance, null).ToString();
break;
case MemberTypes.Property:
value = (member as PropertyInfo)?.GetValue(instance).ToString();
break;
default:
return false;
}
return true;
}
或者如果你真的想要 type 显式
public static bool TryGetValue<T,T2>(T instance, string name, out string value)
{
...
switch (member.MemberType)
{
case MemberTypes.Field:
value = (T2)(member as FieldInfo)?.GetValue(instance);
...
}
更新
这是一个你给出类型的版本,它启动一个实例来获取实例成员,然后在需要时进行处理
public static T GetValue<T>(object instance , MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Field: return (T)(member as FieldInfo)?.GetValue(instance);
case MemberTypes.Method: return (T)(member as MethodInfo)?.Invoke(instance, null);
case MemberTypes.Property: return (T)(member as PropertyInfo)?.GetValue(instance);
default:return default;
}
}
public static bool TryGetValue<T>(Assembly asm, string className, string name, out T value)
{
value = default;
var type = asm.GetType(className);
var instance = Activator.CreateInstance(type);
try
{
var member = type.GetMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.FirstOrDefault();
if (instance == null || member == null) return false;
value = GetValue<T>(instance, member);
}
finally
{
(instance as IDisposable)?.Dispose();
}
return true;
}
用法
Assembly asm = <some assembly>;
if(TryGetValue<uint>(asm, "MyNameSpace.Test1", "TargetVersion", out var out1))
Console.WriteLine(out1);