Как установить свойство динамического объекта C # 4, когда у вас есть имя в другой переменной - PullRequest
43 голосов
/ 13 июня 2010

Я ищу способ изменить свойства объекта dynamic C # 4.0, имя которого известно только во время выполнения.

Есть ли способ сделать что-то вроде (ExpandoObject просто используется в качестве примера, это может быть любой класс, реализующий IDynamicMetaObjectProvider):

string key = "TestKey";
dynamic e = new ExpandoObject();
e[key] = "value";

Что будет эквивалентно:

dynamic e = new ExpandoObject();
e.TestKey = "value";

Или это единственный путь к отражению?

Ответы [ 5 ]

59 голосов
/ 10 апреля 2011

Пол Сасик ответил на аналогичный вопрос на C # 4.0 Динамический против Expando ... где они подходят?

using System;
using System.Dynamic;

class Program
{
    static void Main(string[] args)
    {
        dynamic expando = new ExpandoObject();
        var p = expando as IDictionary<String, object>;
        p["A"] = "New val 1";
        p["B"] = "New val 2";

        Console.WriteLine(expando.A);
        Console.WriteLine(expando.B);
    }
}
16 голосов
/ 13 июня 2010

Не очень легко, нет. Отражение не работает, так как оно предполагает модель обычного типа, которая не полный диапазон dynamic. Если вы на самом деле просто разговариваете с обычными объектами, просто используйте отражение здесь. В противном случае, я ожидаю, что вы, возможно, захотите перепроектировать код, который генерирует компилятор для базового назначения, и настроить его так, чтобы он имел гибкое имя члена. Я буду честен, хотя: это не привлекательный вариант; простое:

dynamic foo = ...
foo.Bar = "abc";

переводится как:

if (<Main>o__SiteContainer0.<>p__Site1 == null)
{
    <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, string, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Bar", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) }));
}
<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, foo, "abc");

Если вам нужен подход, который работает как для динамических, так и для нединамических объектов: FastMember удобен для этого и работает на уровне типа или объекта:

// could be static or DLR 
var wrapped = ObjectAccessor.Create(obj); 
string propName = // something known only at runtime 
Console.WriteLine(wrapped[propName]);

доступно в Nuget и оптимизировано для динамических и нединамических сценариев.

9 голосов
/ 04 июня 2016

Чтобы добавить ответ Джонаса, вам не нужно создавать новую переменную p. Используйте этот подход вместо:

using System;
using System.Dynamic;

class Program
{
    static void Main(string[] args)
    {
        dynamic expando = new ExpandoObject();
        ((IDictionary<String, object>)expando)["A"] = "New val 1";
        ((IDictionary<String, object>)expando)["B"] = "New val 2";

        Console.WriteLine(expando.A);
        Console.WriteLine(expando.B);
    }
}
5 голосов
/ 14 марта 2011

Мой фреймворк с открытым исходным кодом Dynamitey имеет методы для вызова на основе имен строк с использованием DLR.Он выполняет кеширование сайтов привязки и упрощает его до одного вызова метода.он также работает быстрее, чем отражение на нединамических объектах.

Dynamic.InvokeSet(e, "TestKey", "value");
0 голосов
/ 01 декабря 2014

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...