索引切换语句,或等效? .net,C#

我想构建一个接受字符串参数的方法,以及一个我希望根据参数返回特定成员的对象。 所以,最简单的方法是构建一个switch语句:

public GetMemberByName(MyObject myobj, string name) { switch(name){ case "PropOne": return myobj.prop1; case "PropTwo": return myobj.prop2; } } 

这样可以正常工作,但我最终可能会找到一个相当大的列表…所以我很好奇是否有一种方法,无需编写一堆嵌套的if-else结构,以索引方式完成此操作,以便匹配字段通过索引找到而不是通过开关掉落直到找到匹配。

我考虑使用Dictionary来快速访问匹配的字符串(作为关键成员)但是因为我想访问传入对象的成员,所以我不确定这是怎么回事实现。

  • 我特意试图避免reflection等,以便实现非常快速。 我可能会使用代码生成,所以解决方案不需要小/紧等。

  • 我最初正在构建一个字典,但每个对象都在初始化它。 所以我开始将它移动到一个方法,可以根据键 – 一个switch语句查找值。 但由于我不再编入索引,我担心调用此方法的连续查找会很慢。

  • SO:我正在寻找一种方法来结合索引/散列查找(如字典使用)的性能与返回传入对象的特定属性。 我可能会将它放在用于它的每个类中的静态方法中。

这是一种可以使用字典的简单方法:

  Dictionary> propertyNameAssociations; private void BuildPropertyNameAssociations() { propertyNameAssociations = new Dictionary>(); 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; } 

这是一个可以适用于任何类的快速模型(使用reflection而不是switch语句):

 public static object GetMemberByName(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(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:让对象动态存储属性值。

 public GetMemberByName(MyObject myobj, string name) { return myobj.GetProperty(name); } public class MyObject { private Dictionary m_Properties = new Dictionary(); 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:使用reflection。

 public GetMemberByName(MyObject myobj, string name) { return typeof(MyObject).GetProperty(name).GetValue(obj, null); } 

选项3:保持原样。

这是一个合理的选项,因为一旦数字case语句达到某个阈值,字符串数据类型的switch语句将转换为Dictionary查找。 C#3.0编译器的阈值为7。 因此,无论有多少个案例陈述,查找都将是O(1)。 它不会扫描每一个。

您可以使用reflection在运行时动态获取属性。 这是我写的一个小的relection实用程序的片段。 这是一种扩展方法,可以很容易地从类实例中获取属性

 myInstance.GetProperty("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(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); } } 

好吧,假设名称与属性的实际名称匹配(与您的示例不同),这可能最好通过reflection来处理。

你不能用索引来做,但你可以使用reflection。

你可能想尝试使用这样的东西。

 private static readonly Dictionary> _cache = new Dictionary>(); public static T GetProperty(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); if (!_cache.TryGetValue(type, out props)) { props = new Dictionary(); _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); } }