Отримати значення властивості з динамічного об’єкта C # за допомогою рядка (відображення?)


77

Уявіть, що у мене є динамічна змінна:

dynamic d = *something*

Тепер я створюю властивості, для dяких я маю, з іншого боку, масив рядків:

string[] strarray = { 'property1','property2',..... }

Я не знаю назви майна заздалегідь.

Як у коді, після dстворення та витягування strarray з БД, я можу отримати значення?

Я хочу отримати d.property1 , d.property2.

Я бачу, що об’єкт має _dictionaryвнутрішній словник, який містить ключі та значення, як їх отримати?


1
Чи somethingє IDynamicMetaObjectProvider?
Слакс

Перевірте тип виконання somethingв налагоджувачі та подивіться на його загальнодоступних членів.
Слакс

1
Чи можете ви перевірити, що d.GetType()дає вам час роботи?
Томіслав Марковський

Ця відповідь SO показує, як отримати динамічну властивість.
Raymond Chen

можливий дублікат властивостей Loop DynamicObject
nawfal

Відповіді:


107

Я не знаю, чи існує більш елегантний спосіб з динамічно створеними об’єктами, але використання звичайного старого відображення має спрацювати:

var nameOfProperty = "property1";
var propertyInfo = myObject.GetType().GetProperty(nameOfProperty);
var value = propertyInfo.GetValue(myObject, null);

GetPropertyповернеться, nullякщо тип myObjectне містить загальнодоступної власності з цією назвою.


РЕДАГУВАТИ : Якщо об'єкт не є "звичайним" об'єктом, а щось реалізує IDynamicMetaObjectProvider, цей підхід не спрацює. Будь ласка, подивіться на це питання:


32

Це дасть вам усі назви властивостей та значення, визначені у вашій динамічній змінній.

dynamic d = { // your code };
object o = d;
string[] propertyNames = o.GetType().GetProperties().Select(p => p.Name).ToArray();
foreach (var prop in propertyNames)
{
    object propValue = o.GetType().GetProperty(prop).GetValue(o, null);
}

1
Для мене це чудово спрацювало, чого я не зміг досягти для динамічного типу, дякую
Mrinal Kamboj

2
Це працює, лише якщо d є статичним типом. Якщо D є IDynamicMetaObjectProvider (наприклад, JObject), це дасть вам неправильні властивості. Наприклад, якщо d = obj, тоді він не поверне 'x', він поверне необроблені властивості на JObject. JObject obj = JObject.FromObject (новий {x = 123});
Mike S

24

Сподіваюся, це допоможе вам:

public static object GetProperty(object o, string member)
{
    if(o == null) throw new ArgumentNullException("o");
    if(member == null) throw new ArgumentNullException("member");
    Type scope = o.GetType();
    IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
    if(provider != null)
    {
        ParameterExpression param = Expression.Parameter(typeof(object));
        DynamicMetaObject mobj = provider.GetMetaObject(param);
        GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[]{CSharpArgumentInfo.Create(0, null)});
        DynamicMetaObject ret = mobj.BindGetMember(binder);
        BlockExpression final = Expression.Block(
            Expression.Label(CallSiteBinder.UpdateLabel),
            ret.Expression
        );
        LambdaExpression lambda = Expression.Lambda(final, param);
        Delegate del = lambda.Compile();
        return del.DynamicInvoke(o);
    }else{
        return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
    }
}

@Ewerton Минуло досить давно, але я бачу, що він використовує System.Linq.Expressions для прив'язки динамічного геттера до сайту виклику, а компіляцію залишає LambdaExpression . Я не знаю, чи взяв я це з декомпільованого коду, чи десь ще.
IllidanS4 підтримує Моніку

6

Використовуйте наступний код, щоб отримати ім’я та значення властивості динамічного об’єкта.

dynamic d = new { Property1= "Value1", Property2= "Value2"};

var properties = d.GetType().GetProperties();
foreach (var property in properties)
{
    var PropertyName=property.Name; 
//You get "Property1" as a result

  var PropetyValue=d.GetType().GetProperty(property.Name).GetValue(d, null); 
//You get "Value1" as a result

// you can use the PropertyName and Value here
 }

1
Тільки якщо основним типом є звичайний об’єкт. Це не буде працювати для обгорткових об'єктів, таких якPSObject
felixfbecker 02

5
string json = w.JSON;

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

DynamicJsonConverter.DynamicJsonObject obj = 
      (DynamicJsonConverter.DynamicJsonObject)serializer.Deserialize(json, typeof(object));

Тепер obj._Dictionaryмістить словник. Ідеально!

Цей код повинен використовуватися разом з десеріалізацією JSON в динамічний об'єкт C #? + зробіть змінну _dictionary з "private readonly" загальнодоступною в коді там


4

Ви бачили ExpandoObject клас ?

Безпосередньо з опису MSDN : "Представляє об'єкт, члени якого можуть бути динамічно додані та видалені під час виконання".

За допомогою нього ви можете писати такий код:

dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
((IDictionary<String, Object>)employee).Remove("Name");

Назви властивостей невідомі, тому це не спрацює.
user3285954

Код працює (я перевірив його у Visual Studio), оскільки екземпляр працівника є ExpandoObject, тому можливо додавати та видаляти властивості під час виконання (як це пояснюється в офіційній документації MS). Цей код вирішує питання.
ADIMO

Існують інші динамічні об'єкти, крім ExpandoObjectтипу PSObject.
felixfbecker

Ні @ADIMO це не робить. Питання в тому, як отримати доступ до властивості динамічного об’єкта. АЛЕ на даний момент він не знає, які властивості. Вони надходять із масиву рядків. Тож йому потрібно ВИБУТИ ВЛАСНІСТЬ, ЯКЩО
ІСНУЄ ІМЕНЬ,

4

ЯКЩО d був створений Newtonsoft, ви можете використовувати це для читання імен властивостей і значень:

    foreach (JProperty property in d)
    {
        DoSomething(property.Name, property.Value);
    }

1

Думав, це може допомогти комусь у майбутньому.

Якщо ви вже знаєте назву властивості, ви можете зробити щось на зразок наступного:

[HttpPost]
[Route("myRoute")]
public object SomeApiControllerMethod([FromBody] dynamic args){
   var stringValue = args.MyPropertyName.ToString();
   //do something with the string value.  If this is an int, we can int.Parse it, or if it's a string, we can just use it directly.
   //some more code here....
   return stringValue;
}

Назви властивостей невідомі.
user3285954 03

0

Ви можете використовувати " dynamicObject.PropertyName.Value", щоб отримати значення динамічного властивості безпосередньо.

Приклад :

d.property11.Value

1
Питання полягає в отриманні значення з динамічного об'єкта, але він має ім'я властивості як рядок ... наприклад, він хоче зробити щось на зразок того, що ми зробили в Javascript: obj ["property1"], і я вважаю, що це не є відповідь.
bunjeeb

0

Ви можете спробувати так:

d?.property1 , d?.property2

Я протестував його та працюю з .netcore 2.1


1
Питання полягає в отриманні значення з динамічного об'єкта, але він має ім'я властивості як рядок ... наприклад, він хоче зробити щось на зразок того, що ми зробили в Javascript: obj ["property1"], і я вважаю, що це не є відповідь.
bunjeeb
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.