2015-08-03 26 views
5

Mam funkcja, która zwraca typ anonimowy jak tak (uproszczone dla celów poglądowych) ...Dlaczego nie mogę uzyskać dostępu do właściwości anonimowego typu zwracanego z funkcji za pośrednictwem dynamicznego słowa kluczowego?

public object GetPropertyInfo() 
{ 
    return new { 
     PropertyName = "Foo", 
     Value = "Laa" 
    }; 
} 

Kiedy to zrobić ...

dynamic pi = GetPropertyInfo(); 
Console.WriteLine(pi); 

To wyprowadza ten (podobnie jak gdybym to zrobił? 'pi' w najbliższym oknie) ...

{ PropertyName = "A", Value = 44 } 
    PropertyName: "A" 
    Value: 44 

Ale gdybym spróbować zrobić to ...

string propertyName = pi.PropertyName; 

... kompiluje ale zgłasza wyjątek środowiska wykonawczego mówiąc

rzucony wyjątek: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' w System.Core.dll

Dodatkowa informacja: 'obiekt' nie nie zawiera definicji "NazwaOznaczenia"

Co daje? Czego tu mi brakuje?

+0

Co właściwie zwraca funkcja "GetPropertyInfo()"? Jaka jest implementacja? Ten błąd, który otrzymujesz, oznacza, że ​​nie jest to tylko anonimowy obiekt, w przeciwnym razie nie dostaniesz tego błędu. Jeśli 'pi' _was_ było dynamiczne, to ta linia nawet nie wygenerowałaby tego błędu,' propertyName' również byłaby dynamiczna. –

+0

@MarqueIV: Czy są to dwie predefiniowane właściwości? W ogóle nie potrzebujesz dynamiki, chyba że ma ona właściwości dynamiczne. – CharithJ

+0

Dynamika polegała na tym, że próbowałem uzyskać dostęp do właściwości typu anonimowego, przesyłając przez zwracany typ obiektu 'object'. Obiekt nie ma właściwości PropertyType lub Value, stąd użycie opcji Dynamic. Myślę, że problemem jest wewnętrzne ograniczenie, ale nadal jestem ciekawy, jak to wygląda w oknie wyjściowym VS. – MarqueIV

Odpowiedz

8

Problemem jest to, że anonymous types are internal, co oznacza, że ​​nie można uzyskać dostęp do swoich właściwości z dynamic dostępowych własności z projektów innych niż te, które zostały utworzone w. Dynamiczne wiążące traktuje je jako najbliższego publicznego odziedziczonych typu to wie około - object.

Aby to naprawić, możesz zadeklarować typ publiczny, który będzie reprezentował wartości, które spodziewasz się znaleźć w swoim anonimowym typie. Jest to prawdopodobnie dobry pomysł, ponieważ wyraźnie oczekujesz, że skonsumujesz zwrócone właściwości w innych częściach kodu. Użycie zadeklarowanego typu umożliwia również zachowanie bezpieczeństwa typu, co całkowicie eliminuje konieczność stosowania dynamic.

Jeśli koniecznie koniecznością użycie dynamic s tutaj, najlepszym rozwiązaniem jest prawdopodobnie zmienić plik AssemblyInfo.cs aby wewnętrznych właściwości dostępne dla projektu, który próbujesz uzyskać do nich dostęp z:

[assembly:InternalsVisibleTo("MyOtherProject")] 
+0

Ale jeśli są one wewnętrzne, jak mówisz, to dlaczego konsola o nich wie? Nawet wykonanie "? Pi" w bezpośrednim oknie pokazuje PropertyName i Value. Jeśli to możliwe, dlaczego mój kod nie może być? To powiedziawszy, tak, starałem się uniknąć tworzenia dodatkowego typu tylko do tego, ale myślę, że będę musiał pójść tą drogą. – MarqueIV

+0

To, czy był on wewnętrzny, czy nie, nie powinno mieć znaczenia, chyba że obiekt dynamiczny został zwrócony z funkcji innego zespołu. Ale pytanie nie wskazuje nic na źródło przedmiotów. Z tego, co wiemy, wszystko znajduje się w tym samym zespole. –

+1

@MarqueIV: Funkcja 'ToString()' na typach anonimowych jest zaimplementowana automatycznie, aby wyprowadzić wartości wszystkich swoich właściwości. Nie jest to konsola, która rozumie, jak znaleźć swoje właściwości - to ich wewnętrzny kod, który wie, aby wyprowadzić te wartości, gdy wywoływana jest publiczna metoda 'ToString()'. – StriplingWarrior

2

Edit

Według edycję. Podobno nie jest wymagane dynamiczne w ogóle, ponieważ nie ma właściwości dynamicznych. Po prostu stwórz konkretny typ ze swoimi predefiniowanymi właściwościami. Lepiej unikać dynamiki, jeśli to możliwe.

Old Odpowiedź

Musisz użyć ExpandoObject. Odniesienie here.

Rzeczywiście, GetPropertyInfo() powinien zwrócić wartość ExpandoObject.

dynamic foo = this.GetPropertyInfo(); 
    string i = foo.MyPropertyName; 

    private ExpandoObject GetPropertyInfo() 
    { 
     dynamic obj = new ExpandoObject(); 
     obj.PropertyName = "MyPropertyName"; 
     obj.PropertyType = "MyPropertyType"; 

     return obj; 
    } 

Klasa ExpandoObject pozwala dodawać i usuwać członków jego instancji w czasie wykonywania, a także ustawienie i uzyskać wartości tych członków. Ta klasa obsługuje dynamiczne wiązanie, które umożliwia używanie standardowej składni , takiej jak sampleObject.sampleMember, zamiast bardziej złożonej składni jak sampleObject.GetAttribute ("sampleMember").

+1

Nie _ __ __ by być obiektem expando ... nie wiemy nawet, jakie są rzeczywiste przypadki użycia. Sugerowanie, że jest to bardzo mylące. –

+0

Właśnie napisałem coś mówiącego dokładnie. Zawsze będzie to dwie właściwości; Nazwa właściwości i wartość. Myślę, że samo tworzenie konkretnego typu rozwiąże mój problem, ale nadal jestem ciekawy anonimowego typu/wewnętrznej rzeczy, co ma sens, ale nadal nie wyjaśnia, w jaki sposób wyjście/natychmiastowe okno zna więcej niż prosta wartość ToString . – MarqueIV

+0

@JeffMercado: Myślę, że masz rację zgodnie z edycją. – CharithJ

1

ponadto, można użyć System.Reflection

object D = GetPropertyInfo(); 
Type t = D.GetType(); // get object's type 
PropertyInfo p = t.GetProperty("PropertyName"); // look up for the property: 
object P = p.GetValue(D, null); // get the value 

Fiddle demo