индексируемый оператор переключения, или эквивалентный? .NET, C#

Я хочу создать метод, который принимает строковый параметрический усилитель и объект, которого я хотел бы возвратить конкретного члена на основе параметрического усилителя. Так, самый легкий метод должен создать оператор переключения:

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

Это хорошо работает, но я могу волновать с довольно большим списком... Таким образом, мне было любопытно, если существует путь, не пишущий набор вложенных, если еще структуры, для выполнения этого индексируемым способом, так, чтобы поле соответствия было найдено индексом вместо того, чтобы проваливаться переключателя до соответствия, найдены.

Я рассмотрел использование a Dictionary<string, something> для предоставления доступа к соответствующим строкам (в качестве главного члена), но так как я желаю получить доступ к члену переданного - в объекте я не уверен, как это могло быть выполнено.

  • Я конкретно стараюсь избегать отражения и т.д., чтобы иметь очень внедрение FAST. Я буду, вероятно, использовать генерацию кода, таким образом, решение не должно будет быть маленьким/трудным и т.д.

  • Я первоначально создавал словарь, но каждый объект инициализировал его. Таким образом, я начал перемещать это в отдельный метод, который может искать значения на основе ключей - оператор переключения. Но так как я больше не индексируюсь, я боюсь, что непрерывные поиски, называя этот метод были бы медленными.

  • ТАК: Я ищу способ объединиться, производительность индексировала/хешировала поиск (как использование Словаря) с возвратом особых свойств переданного - в объекте. Я, вероятно, помещу это в статический метод в каждом классе, для которого он используется.

6
задан Null 10 August 2015 в 16:24
поделиться

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;
    }
7
ответ дан 8 December 2019 в 05:52
поделиться

Есть несколько вариантов, которые вы можете попробовать.

Вариант 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: Оставить как есть.

Это разумный вариант, поскольку операторы switch для строковых типов данных будут преобразованы в поиск Dictionary , как только операторы числового регистра достигнут определенного порога. Для компилятора C # 3.0 этот порог равен 7. Таким образом, поиск будет O (1) независимо от количества операторов case. Он не будет сканировать каждый из них.

5
ответ дан 8 December 2019 в 05:52
поделиться

Вот быстрый макет того, что может работать для любого класса (с использованием отражения, а не оператора переключения):

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

Очевидно, вы могли бы захотеть провести дополнительную проверку ошибок, но это было бы началом.

Я также не зря возвратил объект типа из методов. Это позволяет вызывающей стороне обрабатывать приведение значения, как они считают нужным (если им вообще нужно приведение).

8
ответ дан 8 December 2019 в 05:52
поделиться

Вы можете использовать отражение для динамического получения свойства во время выполнения. Вот отрывок из небольшой утилиты отражения, которую я написал. Это написано как метод расширения, который легко позволит вам получить свойство из экземпляра вашего класса

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);
    }
}
2
ответ дан 8 December 2019 в 05:52
поделиться

Ну, если предположить, что Name соответствует реальному имени свойства (в отличие от вашего примера), это, вероятно, лучше всего будет обработать через отражение.

0
ответ дан 8 December 2019 в 05:52
поделиться

Вы не можете сделать это с помощью индекса, но вы можете использовать отражение.

0
ответ дан 8 December 2019 в 05:52
поделиться

Вы можете попробовать использовать что-то вроде этого.

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);
    }
}
0
ответ дан 8 December 2019 в 05:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: