我想构建一个接受字符串参数的方法,以及一个我希望根据参数返回特定成员的对象。因此,最简单的方法是构建一个switch语句:
public GetMemberByName(MyObject myobj, string name)
{
switch(name){
case "PropOne": return myobj.prop1;
case "PropTwo": return myobj.prop2;
}
}
这样可以正常工作,但我最终可能会找到一个相当大的列表...所以我很好奇是否有一种方法,而不是编写一堆嵌套的if-else结构,以索引的方式实现这一点,以便匹配字段是通过索引找到的,而不是通过开关掉落,直到找到匹配为止。
我考虑使用Dictionary<string, something>
来快速访问匹配的字符串(作为关键成员),但由于我想访问传入对象的成员,我不知道这是怎么回事可以完成。
我特意试图避免反射等,以便实现非常快速。我可能会使用代码生成,因此解决方案不需要小/紧等等。
我最初正在构建一个字典,但每个对象都在初始化它。所以我开始将它移动到一个方法,可以根据键 - 一个switch语句查找值。但由于我不再编入索引,我担心调用此方法的连续查找会很慢。
SO:我正在寻找一种方法来将索引/散列查找(如Dictionary使用)的性能与返回传入对象的特定属性相结合。我可能会将它放在用于它的每个类中的静态方法中。
答案 0 :(得分:8)
这是一个可以适用于任何类的快速模型(使用反射而不是switch语句):
public static object GetMemberByName<T>(T obj, string name)
{
PropertyInfo prop = typeof(T).GetProperty(name);
if(prop != null)
return prop.GetValue(obj, null);
throw new ArgumentException("Named property doesn't exist.");
}
或扩展方法版本(仍可用于任何对象类型):
public static object GetMemberByName<T>(this T obj, string name)
{
PropertyInfo prop = typeof(T).GetProperty(name);
if(prop != null)
return prop.GetValue(obj, null);
throw new ArgumentException("Named property doesn't exist.");
}
显然你可能想要做一些额外的错误检查,但这将是一个开始。
我还从方法中返回了类型对象,原因很简单。这允许调用者处理他们认为合适的值(如果他们需要完全投射)。
答案 1 :(得分:7)
这是一种使用字典的简便方法:
Dictionary<string, Func<MyObject, object>> propertyNameAssociations;
private void BuildPropertyNameAssociations()
{
propertyNameAssociations = new Dictionary<string, Func<MyObject, object>>();
propertyNameAssociations.Add("PropOne", x => x.prop1);
propertyNameAssociations.Add("PropTwo", x => x.prop2);
}
public object GetMemberByName(MyObject myobj, string name)
{
if (propertyNameAssociations.Contains(name))
return propertyNameAssociations[name](myobj);
else
return null;
}
答案 2 :(得分:5)
您可以尝试一些选项。
选项1:让对象动态存储属性值。
public GetMemberByName(MyObject myobj, string name)
{
return myobj.GetProperty(name);
}
public class MyObject
{
private Dictionary<string, object> m_Properties = new Dictionary<string, object>();
public object GetProperty(string name)
{
return m_Properties[name];
}
public void SetProperty(string name, object value)
{
m_Properties[name] = value;
}
public object Prop1
{
get { return GetProperty("PropOne"); }
set { SetProperty("PropOne", value); }
}
public object Prop2
{
get { return GetProperty("PropTwo"); }
set { SetProperty("PropTwo", value); }
}
}
选项2:使用反射。
public GetMemberByName(MyObject myobj, string name)
{
return typeof(MyObject).GetProperty(name).GetValue(obj, null);
}
选项3:保持原样。
这是一个合理的选择,因为一旦数字case语句达到某个阈值,字符串数据类型的switch语句将转换为Dictionary
查找。 C#3.0编译器的阈值为7。因此,无论有多少个案例陈述,查找都将是O(1)。它不会扫描每一个。
答案 3 :(得分:2)
您可以使用reflection
在运行时动态获取属性。这是我写的一个小的relection实用程序的片段。这是一种扩展方法,可以轻松地从类实例中获取属性
myInstance.GetProperty<string>("Title"); // Replace 'string' with the proper return value.
代码:
public static class ReflectionExtensions
{
private const BindingFlags DefaultFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
public static T GetProperty<T>(this object instance, string propertyName)
{
PropertyInfo property = GetPropertyInfo(instance, propertyName);
if (property == null)
{
var message = string.Format("The Type, '{0}' does not implement a '{1}' property", instance.GetType().AssemblyQualifiedName, propertyName);
throw new NotImplementedException(message);
}
return (T)property.GetValue(instance, null);
}
private static PropertyInfo GetPropertyInfo(object instance, string propertyName)
{
Type type = instance.GetType();
return type.GetProperty(propertyName, DefaultFlags);
}
}
答案 4 :(得分:0)
好吧,假设名称与属性的实际名称匹配(与您的示例不同),这可能最好通过反射来处理。
答案 5 :(得分:0)
你不能用索引来做,但你可以使用反射。
答案 6 :(得分:0)
你可能想尝试使用这样的东西。
private static readonly Dictionary<Type, Dictionary<string, PropertyInfo>> _cache = new Dictionary<Type,Dictionary<string,PropertyInfo>>();
public static T GetProperty<T>(object obj, string name)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
else if (name == null)
{
throw new ArgumentNullException("name");
}
lock (_cache)
{
var type = obj.GetType();
var props = default(Dictionary<string, PropertyInfo>);
if (!_cache.TryGetValue(type, out props))
{
props = new Dictionary<string, PropertyInfo>();
_cache.Add(type, props);
}
var prop = default(PropertyInfo);
if (!props.TryGetValue(name, out prop))
{
prop = type.GetProperty(name);
if (prop == null)
{
throw new MissingMemberException(name);
}
props.Add(name, prop);
}
return (T)prop.GetValue(obj, null);
}
}