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

时间:2010-07-29 18:10:59

标签: c# dictionary switch-statement

我想构建一个接受字符串参数的方法,以及一个我希望根据参数返回特定成员的对象。因此,最简单的方法是构建一个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使用)的性能与返回传入对象的特定属性相结合。我可能会将它放在用于它的每个类中的静态方法中。

7 个答案:

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