2013-04-23 3 views
1

Как создать сложную структуру анонимного объекта public внутри объекта dynamic?Комплекс анонимных объектов для динамических общедоступных свойств

Анонимные объекты отмечены как internal, так что я ищу творческий способ обойти это.

// This is the library I control 
public void SendObject() { 
    var anonymous = new { 
     Text = "Test", 
     SubItem = new { 
      SubText = "Bla", 
      SubSub = new { 
       SubSubText = "Baha" 
      } 
     } 
    }; 
} 

dynamic dyn = ExposeAnonymous(anonymous); // Perform voodoo 

var result = ExternalLibrary.GetSpecialProperty(dyn); 

// External library I don't control 
public object GetSpecialProperty(dynamic dyn) { 
    return dyn.SubItem.SubSub.SubSubText; 
} 

Проблема заключается при отправке dynamic в других внешних библиотек, , что я не контролируют, вы получите ошибку, как:

«объект» не содержит определение для «SubItem».

+2

работает для меня .... –

+3

Работающих здесь, а также (после замены запятой в строке 4 с '') – keyboardP

+4

Решающей частью является «другими библиотеками» - которые, конечно, ISN» t, продемонстрированный в фрагменте ... –

ответ

6

Проблема заключается при передаче динамического других библиотек,

... И есть протирание. Анонимные типы объявляются компилятором C# internal, что означает, что другие сборки не имеют к ним доступа.

Либо прекратите использование анонимных типов, либо используйте [InternalsVisibleToAttribute], чтобы сделать вид видимым для других сборок. В сборку, содержащую тип, который создает экземпляр анонимного типа, используйте:

[InternalsVisibleTo("ExternalLibrary")] 

(я на самом деле ожидать, что вопрос будет на SubItem, а не SubSub ...)

+0

Это (багги?) библиотека, которую я не могу контролировать, поэтому 'InternalsVisibleToAttribute' не будет работать. –

+0

@SebNilsson: * Что это за библиотека, которую вы не можете контролировать? Тот, кто возвращает объект, или тот, кто его потребляет? Если вы не можете изменить объект, возвращающий объект, вам может понадобиться прибегнуть к отражению. (Даже это не сработает, если вам не доверяют должным образом.) –

+0

Я думаю, может быть, этот вопрос слишком не соответствует контексту, и я надеялся получить quickfix. Это, в основном, библиотека RazorEngine, которая имеет проблемы с динамическими анонимными типами. Но «перестать использовать анонимный» для многих, многие разные структуры данных - это не вариант. –

5

Anonymous типы - internal, а DLR выполняет тот же анализ доступности во время выполнения, который компилятор выполняет во время компиляции. Таким образом, вы не можете получить доступ к элементам анонимного типа из другой сборки, используя dynamic.

Одним из вариантов может быть использование ExpandoObject:

 dynamic a = new ExpandoObject(); 
     a.Text = "Test"; 
     a.SubItem = new ExpandoObject(); 
     a.SubItem.SubText = "Blah"; 
     a.SubItem.SubSub = new ExpandoObject(); 
     a.SubItem.SubSub.Text = "Baha"; 

Это своего рода некрасиво так, вы могли бы держать анонимный тип и использовать вспомогательный метод для рекурсивного преобразовать в ExpandoObject:

public static dynamic ConvertToExpando(object obj) 
    { 
     IDictionary<string, object> expando = new ExpandoObject(); 
      foreach(var pi in obj.GetType().GetProperties()) 
      { 
       // there doesn't seem to be a way to know if it is an anonymous type directly. So I use IsPublic here. 
       if (pi.PropertyType.IsPublic) 
       { 
        expando[pi.Name] = pi.GetValue(obj);      
       } 
       else 
       { 
        expando[pi.Name] = ConvertToExpando(pi.GetValue(obj)); 
       } 
      } 
     return expando; 
    } 

Это делает «Выполнять вуду», в котором вы нуждаетесь.

+0

Должно быть возможно что-то написать использовать отражение для преобразования анонимного типа в ExpandoObject рекурсивно, тоже ... –

+0

Это было одно из решений, на которые я смотрел и боялся получения. Я знаю, что это работает, но выглядит ужасно ... –

+1

@SebNilsson Вам сложно угодить. Он должен работать и быть красивым, да. Я добавил вспомогательный метод, который рекурсивно преобразует анонимный тип в 'ExpandoObject' (как предложил Джон Скит). –

1

С помощью рамки openprom ImpromptuInterface (в nuget) вы можете создавать сложные графы expando с помощью inline syntax.

dynamic New = Builder.New<ExpandoObject>(); 

dynamic dyn = New.Obj(
     Text: "Test", 
     SubItem: New.Obj(
      SubText: "Bla", 
      SubSub: New.Obj(
       SubSubText: "Baha" 
      ) 
     ) 
    ); 
Смежные вопросы