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

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

//  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», который каким-то образом реализует этот тип функциональности. Глина на CodePlex
Скотт Хансельман по теме

Ответы [ 3 ]

6 голосов
/ 14 августа 2010

Это можно сделать. Вам просто нужно переопределить 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);
3 голосов
/ 06 мая 2010

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

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.

2 голосов
/ 18 июля 2011

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

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