C# Использование ключевого слова Dynamic для доступа к свойствам через строки без отражения

Я хотел бы написать что-то похожее на следующее:

//  I will pass in a number of "properties" specified as strings that I want modified
string[] properties = new [] { "AllowEdit", "AllowDelete" };

//  Casting the component I'm using to a dynamic object of some sort ?
dynamic d = myGridComponent;

//  Iterate over the strings and set the properties
foreach(var s in properties) 
{
  //d.s = true; // 
  //d[s] = true; // this format would be ideal
}

Мне было интересно, есть ли простой способ сделать это без использования Reflection [.GetProperty(...).GetValue(...,...)] с использованием нового ключевого слова C# 4.0: dynamic.

Кажется, что может быть какой-то способ ... Я просто не уверен в точном механизме и не смог найти подходящий ресурс, чтобы собрать все части вместе.

Мысли ?

[EDIT] Похоже, что есть пакет под названием «Clay», который каким-то образом реализует этот тип функциональности. Clay на CodePlex
Скотт Хансельман по теме


person Matthew M.    schedule 06.05.2010    source источник


Ответы (3)


Это может быть сделано. Вам просто нужно переопределить TryGetIndex на DynamicObject. Мне нужно было что-то похожее для вызова статических членов типа, но, надеюсь, вы поняли идею. Имейте в виду, что в настоящее время это не работает с методами с аргументами универсального типа или перегруженными методами, что ограничивает его полезность:

internal class StaticMembersDynamicWrapper : DynamicObject
{
    private readonly IDictionary<String, MemberInfo> staticMembers = new Dictionary<string, MemberInfo>();
    private readonly Type type;

    public StaticMembersDynamicWrapper(Type type)
    {
        this.type = type;
        type.GetMembers(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public)
            .Each(member => staticMembers[member.Name] = member);
    }

    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
    {
        var name = indexes[0] as string;

        MemberInfo member;

        if (false == staticMembers.TryGetValue(name, out member))
        {
            result = null;
            return false;
        }

        var prop = member as PropertyInfo;
        if (prop != null)
        {
            result = prop.GetValue(null, null);
            return true;
        }
        var method = member as MethodInfo;
        if (method != null)
        {
            var parameterTypes = (from p in method.GetParameters()
                                  select p.ParameterType).ToArray();
            var delegateType = method.ReturnType != typeof (void)
                            ? Expression.GetFuncType(parameterTypes.Union(new[]{method.ReturnType}).ToArray())
                            : Expression.GetActionType(parameterTypes);
            result = Delegate.CreateDelegate(delegateType, method);
            return true;
        }
        result = null;
        return false;
    }
}

dynamic d = new StaticMembersDynamicWrapper(typeof(string));
var result = d["IsNullOrEmpty"](String.Empty);
person João Bragança    schedule 13.08.2010
comment
Вау, действительно классное решение, я искал именно это! - person Allen Rice; 28.06.2012

dynamic в С# этого не предлагает. С вашими двумя примерами:

d.s = true; // this looks for a property or field called "s"
d[s] = true; // this looks for an indexer that matches the string/bool signature

Вы можете написать тот же код, который предлагает dynamic, но это будет намного сложнее, чем просто использование отражения. Либо используйте отражение (согласно вашему примеру), либо, если вам нужно его оптимизировать, вы можете дополнительно обернуть его делегатом через Expression или Delegate.CreateDelegate.

person Marc Gravell    schedule 06.05.2010
comment
Не думал так, но стоит спросить! Определенно одна функция, которой мне не хватает в PHP.. конечно, по крайней мере, есть способы сделать это, просто подумал, что было бы неплохо, если бы к динамическим объектам можно было получить доступ через Indexer. :) - Мэтью - person Matthew M.; 07.05.2010

Платформа с открытым исходным кодом Impromptu-interface, доступная через nuget, инкапсулирует код, который динамически генерируется в полностью динамичная мода. Это не так быстро, как использование динамического ключевого слова, но быстрее, чем отражение.

foreach(var s in properties) 
{
  //d.s = true; 
  Impromptu.InvokeSet(d, s, true);
}
person jbtule    schedule 18.07.2011