2010-06-07 14 views
25

Der folgende Code funktioniert hervorragend. Wenn sich die Methoden Get und Use in verschiedenen Assemblys befinden, schlägt der Code mit einer RuntimeBinderException fehl. Dies ist darauf zurückzuführen, dass das .NET-Laufzeitsystem nur innerhalb von Baugruppen die Anonymität von Typen (<string, int>) garantiert.Geben Sie dynamisch anonymen Typ über Baugruppengrenzen zurück/konsumieren

Gibt es eine Möglichkeit, das Laufzeitsystem zu täuschen, um dies zu überwinden? Ich kann das Objekt im Debugger auf der Seite Use untersuchen, und der Debugger kann die relevanten Eigenschaften sehen.

class Program 
{ 
    static void Main(string[] args) 
    { 
     UsePerson(); 
     Console.ReadLine(); 
    } 

    public static void UsePerson() 
    { 
     var person = GetPerson(); 

     Console.WriteLine(person.Name); 
    } 

    public static dynamic GetPerson() 
    { 
     return new { Name = "Foo", Age = 30 }; 
    } 
} 

Antwort

31

Verwenden Sie eine ExpandoObject anstelle eines anonymen Typs. Dies sollte Ihnen ermöglichen, Montage Grenzen sicher zu überqueren:

public static dynamic GetPerson() 
{ 
    dynamic person = new ExpandoObject(); 
    person.Name = "Foo"; 
    person.Age = 30; 

    return person; 
} 

Im Allgemeinen anonyme Typen sollten wirklich nur innerhalb der gleichen Methode verwendet werden, in dem sie erzeugt werden. Die Rückgabe eines anonymen Typs aus einer Methode führt im Allgemeinen zu mehr Problemen als zur Lösung.

8

Die Ursache des Problems besteht darin, dass anonyme Typen in Assemblys intern sind. Aus diesem Grund können Sie in Dynamic Language Runtime nicht auf Eigenschaften einer anderen Assembly zugreifen.

Eine Lösung wird in dieser post erläutert. Sie können ein benutzerdefiniertes Attribut in die Assembly einfügen, das den anonymen Typ definiert, sodass die andere Assembly auf ihre internen Elemente zugreifen kann.

Eine andere Lösung gibt ein Objekt einer öffentlichen Klasse (mit öffentlichen Eigenschaften) zurück. Das wird natürlich die Vorteile des anonymen Typs zunichte machen.

Eine dritte Lösung wäre ein ExpandoObject, wie von Reed Copsey vorgeschlagen.

Wenn Sie immer noch den anonymen Typ verwenden möchten, könnten Sie eine dynamische Klasse schreiben, die jeden anonymen Typ "dekoriert" und seine Mitglieder verfügbar macht. Eine solche Klasse müsste die Schnittstelle IDynamicMetaObjectProvider implementieren und über Reflektion auf das dekorierte Objekt zugreifen. Möglicherweise wurde dieses Zeug bereits von jemandem da draußen implementiert.

+0

Der Link, der auf den Beitrag zeigt, ist gebrochen –

+1

Lösung "1" in der obigen Post ist eigentlich ziemlich interessant. Grundsätzlich [assembly: InternalsVisibleTo ("SomeOtherAssembly")] in Ihrer Assemblyinfo.cs funktioniert ziemlich gut. – OFConsulting

0

improvisierte-Schnittstelle

http://code.google.com/p/impromptu-interface/

lassen Sie die den anonymen Typ-Instanz über die Grenzen hinweg verwenden, aber Sie müssen eine Schnittstelle deklarieren, die mit der Signatur übereinstimmt oder zumindest mit der Signatur, auf die Sie zugreifen möchten.

1

Hier ist ein armer Mann Workaround; Newtonsoft.Json zur Rettung, als Serialisierung Roundtrip generiert dynamischen Typ Instanzen sichtbar für Ihre/Arbeitsassembly.

public static class TypeExt 
{ 
    // roundtrip json serialization to enable access to dynamic members and properties originating from another assembly 
    public static T JClone<T>(this T source) { return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source)); } 
} 
Verwandte Themen