Как установить свойство динамического объекта С# 4, если у вас есть имя в другой переменной
Я ищу способ изменения свойств объекта dynamic
С# 4.0 с именем свойства, известного только во время выполнения.
Есть ли способ сделать что-то вроде (ExpandoObject
просто используется в качестве примера, это может быть любой класс, который реализует IDynamicMetaObjectProvider
):
string key = "TestKey";
dynamic e = new ExpandoObject();
e[key] = "value";
Что было бы эквивалентно:
dynamic e = new ExpandoObject();
e.TestKey = "value";
Или это единственный способ отражения?
Ответы
Ответ 1
Не очень легко, нет. Отражение не работает, так как оно предполагает модель обычного типа, которая не является полным диапазоном 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 и сильно оптимизирован для динамических и нединамических сценариев.
Ответ 2
Пол Сасик ответил на аналогичный вопрос в С# 4.0 Dynamic vs 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);
}
}
Ответ 3
Чтобы добавить к ответу Джонаса, вам не нужно создавать новый var 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);
}
}
Ответ 4
В моей открытой исходной структуре Dynamitey есть методы для вызова на основе имен строк с использованием DLR. Он выполняет работу кэширования сайтов привязки и упрощает его до одного вызова метода. он также работает быстрее, чем отражение на нединамических объектах.
Dynamic.InvokeSet(e, "TestKey", "value");
Ответ 5
fast-member может соответствовать счету - похоже, что он генерирует IL на лету, но кэширует его так быстро, как только первое использование.