Jak stworzyć własny typ dynamiczny lub obiekt dynamiczny w C #?

142

Jest na przykład właściwość klasy ViewBagControllerBase i możemy dynamicznie pobierać / ustawiać wartości i dodawać dowolną liczbę dodatkowych pól lub właściwości do tego obiektu, co jest fajne. Chcę użyć czegoś takiego, poza aplikacją MVC i Controllerklasą w innych rodzaje aplikacji. Kiedy próbowałem stworzyć obiekt dynamiczny i ustawić jego właściwość jak poniżej:

1. dynamic MyDynamic = new { A="a" };
2. MyDynamic.A = "asd";
3. Console.WriteLine(MyDynamic.A);

Otrzymałem RuntimeBinderExceptionz wiadomością Właściwość lub indeksator '<> f__AnonymousType0.A' nie może być przypisany - jest odczytywany tylko w linii 2. Również sugeruję, że nie jest to do końca to, czego szukam. Może jest jakaś klasa, która pozwoli mi zrobić coś takiego:

??? MyDynamic = new ???();
MyDynamic.A = "A";
MyDynamic.B = "B";
MyDynamic.C = DateTime.Now;
MyDynamic.TheAnswerToLifeTheUniverseAndEverything = 42;

z dynamicznymi właściwościami dodawania i ustawiania.

Dmytro
źródło

Odpowiedzi:

293
dynamic MyDynamic = new System.Dynamic.ExpandoObject();
MyDynamic.A = "A";
MyDynamic.B = "B";
MyDynamic.C = "C";
MyDynamic.Number = 12;
MyDynamic.MyMethod = new Func<int>(() => 
{ 
    return 55; 
});
Console.WriteLine(MyDynamic.MyMethod());

Przeczytaj więcej o klasie ExpandoObject i więcej przykładów: Reprezentuje obiekt, którego elementy członkowskie mogą być dynamicznie dodawane i usuwane w czasie wykonywania.

Mario Sannum
źródło
3
Zagłosuj na tę funkcję w programie Visual Studio UserVoice .
orad
35

Niedawno musiałem pójść o krok dalej, a mianowicie uczynić dodatki właściwości w obiekcie dynamicznym, same dynamiczne, w oparciu o wpisy zdefiniowane przez użytkownika. Przykłady tutaj oraz z dokumentacji ExpandoObject firmy Microsoft nie dotyczą w szczególności dynamicznego dodawania właściwości, ale można je wywnioskować na podstawie sposobu wyliczania i usuwania właściwości. W każdym razie pomyślałem, że to może być dla kogoś pomocne. Oto niezwykle uproszczona wersja sposobu dodawania prawdziwie dynamicznych właściwości do ExpandoObject (ignorując słowo kluczowe i inne sposoby obsługi):

        // my pretend dataset
        List<string> fields = new List<string>();
        // my 'columns'
        fields.Add("this_thing");
        fields.Add("that_thing");
        fields.Add("the_other");

        dynamic exo = new System.Dynamic.ExpandoObject();

        foreach (string field in fields)
        {
            ((IDictionary<String, Object>)exo).Add(field, field + "_data");
        }

        // output - from Json.Net NuGet package
        textBox1.Text = Newtonsoft.Json.JsonConvert.SerializeObject(exo);
AlienFromCA
źródło
Czy ktoś wie, dlaczego musimy wpisać rzut, aby uzyskać dostęp do Addmetody? Wydaje mi się to dziwne.
Vimes
Dzieje się tak, ponieważ ExpandoObject nie ujawnia bezpośredniej metody Add. Jeśli spróbujesz użyć .Add, potraktuje to wyrażenie tak, jakbyś chciał dodać element członkowski „Add” do obiektu. Musisz ujawnić podstawową strukturę danych, w zasadzie przechodząc do interfejsu Dictionary, aby uzyskać dostęp do metody Add. Dotyczy to również usuwania członka lub czegokolwiek innego, co jest oferowane w słowniku, ale nie jest ujawniane w samym ExpandoObject. Nowsza dokumentacja wydaje się lepiej wyjaśniać to wymaganie: docs.microsoft.com/en-us/dotnet/api/ ...
AlienFromCA
Dzięki, Alien. Czy przychodzi Ci do głowy jakiś powód, dla którego API zostało zaprojektowane w ten sposób, poza przypadkową decyzją? O ile wiem, to kiepski projekt API.
Vimes
32

ExpandoObject jest tym, czego szukasz.

dynamic MyDynamic = new ExpandoObject(); // note, the type MUST be dynamic to use dynamic invoking.
MyDynamic.A = "A";
MyDynamic.B = "B";
MyDynamic.C = "C";
MyDynamic.TheAnswerToLifeTheUniverseAndEverything = 42;
nothrow
źródło
11

Możesz użyć tego, ExpandoObject Classco jest w System.Dynamicprzestrzeni nazw.

dynamic MyDynamic = new ExpandoObject();
MyDynamic.A = "A";
MyDynamic.B = "B";
MyDynamic.C = "C";
MyDynamic.SomeProperty = SomeValue
MyDynamic.number = 10;
MyDynamic.Increment = (Action)(() => { MyDynamic.number++; });

Więcej informacji można znaleźć w ExpandoObject MSDN

Kishore Kumar
źródło
9
dynamic myDynamic = new { PropertyOne = true, PropertyTwo = false};
smedasn
źródło
7
dynamic MyDynamic = new ExpandoObject();
Davecz
źródło
7
 var data = new { studentId = 1, StudentName = "abc" };  

Lub wartość jest obecna

  var data = new { studentId, StudentName };
Skała
źródło