代码之家  ›  专栏  ›  技术社区  ›  Brady Moritz

索引开关语句,或等效语句。净值,C#

  •  6
  • Brady Moritz  · 技术社区  · 16 年前

    我想建立一个方法,它接受一个字符串param和一个对象,我想返回一个基于param的特定成员。因此,最简单的方法是构建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语句。但由于我不再被编入索引,我担心调用此方法的连续查找会很慢。

    • 所以:我正在寻找一种方法,将索引/哈希查找(就像字典使用的)的性能与返回传入对象的特定属性结合起来。我可能会把它放在它所用于的每个类中的一个静态方法中。

    7 回复  |  直到 11 年前
        1
  •  7
  •   Jeffrey L Whitledge    16 年前

    下面是一个使用字典的简单方法:

        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
  •  8
  •   Justin Niessner    16 年前

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

    显然,您可能需要执行一些额外的错误检查,但这只是一个开始。

        3
  •  5
  •   Brian Gideon    16 年前

    有几个选择你可以尝试。

    选项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);
    }
    

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

        4
  •  2
  •   Wallace Breza    16 年前

    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);
        }
    }
    
        5
  •  0
  •   James Curran    16 年前

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

        6
  •  0
  •   Coding Flow    16 年前

    你不能用索引,但你可以用反射。

        7
  •  0
  •   ChaosPandion    16 年前

    你可以试着用这样的东西。

    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);
        }
    }