100 Stimmen

Wie wird eine neue anonyme Klasse dynamisch?

In C# 3.0 können Sie anonyme Klassen mit der folgenden Syntax erstellen

var o1 = new { Id = 1, Name = "Foo" };

Gibt es eine Möglichkeit, diese anonyme Klasse dynamisch in einer Variablen zu erstellen?


Exemple :

var o1 = new { Id = 1, Name = "Foo" };
var o2 = new { SQ = 2, Birth = DateTime.Now };

Dynamisch erstellen Beispiel:

var o1 = DynamicNewAnonymous(new NameValuePair("Id", 1), new NameValuePair("Name", "Foo"));
var o2 = DynamicNewAnonymous(new NameValuePair("SQ", 2), new NameValuePair("Birth", 
DateTime.Now));

Weil ich es tun muss:

dynamic o1 = new ExpandObject(); 
o1."ID" = 1;    <--"ID" is dynamic name
o1."Name" = "Foo";  <--"Name" is dynamic name

Und Szene1:

void ShowPropertiesValue(object o)
{
  Type oType = o.GetType();
  foreach(var pi in oType.GetProperties())
  {
    Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
  }
}

wenn ich anrufe:

dynamic o1 = new ExpandObject();
o1.Name = "123";
ShowPropertiesValue(o1);

Sie kann das Ergebnis nicht anzeigen:

Name = 123

Und auch ich, wie die ExpandoObject zu AnonymouseType konvertieren?

Type type = o1.GetType();
type.GetProperties();   <--I hope it can get all property of o1

Zuletzt ändere ich die Methode ShowPropertiesValue()

void ShowPropertiesValue(object o)
{
  if( o is static object ) <--How to check it is dynamic or static object?
  {
    Type oType = o.GetType();
    foreach(var pi in oType.GetProperties())
    {
      Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
    }
  }
  else if( o is dynamic object )  <--How to check it is dynamic or static object?
  {
    foreach(var pi in ??? )  <--How to get common dynamic object's properties info ?
    {
      Console.WriteLine("{0}={1}", pi.Name, pi.GetValue(o, null));
    } 
  }
}

Wie implementiert man die Methode DynamicNewAnonymous oder wie ändert man ShowPropertiesValue()?

Meine Beweggründe sind:

dynamic o1 = new MyDynamic();
o1.Name = "abc";
Type o1Type = o1.GetType();
var props = o1Type.GetProperties(); <--I hope can get the Name Property

Wenn ich die GetType-Methode von dynamicObject einhaken kann, und Compel in einen stark typisierten Typ konvertieren. Die oben genannten Seamless-Code kann gut funktionieren.

0 Stimmen

ExpandoObject, nicht ExpandObject (mit 'o').

80voto

Steven Sudit Punkte 19005

Anonyme Typen sind einfach normale Typen, die implizit deklariert werden. Sie haben wenig zu tun mit dynamic .

Wenn Sie nun eine ExpandoObject und referenzieren ihn über eine dynamic können Sie spontan Felder hinzufügen oder entfernen.

modifier

Natürlich können Sie das: werfen Sie es einfach an IDictionary<string, object> . Dann können Sie den Indexer verwenden.

Sie verwenden die gleiche Casting-Technik, um über die Felder zu iterieren:

dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;

foreach (var property in (IDictionary<string, object>)employee)
{
    Console.WriteLine(property.Key + ": " + property.Value);
}
// This code example produces the following output:
// Name: John Smith
// Age: 33

Den obigen Code und weitere Informationen finden Sie, wenn Sie auf diesen Link klicken.

2 Stimmen

Aber ExpandoObject kann das nicht: dynamic o1 = new ExpandObject(); o1."ID" = 1; o1."Name" = "Foo";

0 Stimmen

Aber es kann auch nicht zu tun: Type o1Type = o1.GetType(); var props = o1Type.GetProperties(); props ist leer

3 Stimmen

Sie sagen damit nur, dass dynamische Eigenschaften nicht mit stark typisierten Eigenschaften identisch sind. Das ist trivialerweise wahr.

17voto

Daniel B Punkte 3266

Sie können ein ExpandoObject wie folgt erstellen:

IDictionary<string,object> expando = new ExpandoObject();
expando["Name"] = value;

Nach der Umwandlung in einen dynamischen Wert sehen diese Werte wie Eigenschaften aus:

dynamic d = expando;
Console.WriteLine(d.Name);

Es handelt sich jedoch nicht um tatsächliche Eigenschaften, auf die mit Reflection nicht zugegriffen werden kann. Die folgende Anweisung gibt also null zurück:

d.GetType().GetProperty("Name")

4voto

Svetlana Gurskaya Punkte 169

Natürlich ist es möglich, dynamische Klassen mit sehr coolen ExpandoObject Klasse zu erstellen. Aber vor kurzem arbeitete ich auf Projekt und konfrontiert, dass Expando Object in nicht das gleiche Format auf xml als eine einfache anonyme Klasse serealisiert ist, es war schade =( , deshalb habe ich beschlossen, meine eigene Klasse zu erstellen und teilen Sie es mit Ihnen. Sie verwendet Reflexion und dynamische Direktive, baut Assembly, Klasse und Instanz wirklich dynamisch auf. Sie können Eigenschaften hinzufügen, entfernen und ändern, die in Ihrer Klasse enthalten sind. Hier ist sie:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using static YourNamespace.DynamicTypeBuilderTest;

namespace YourNamespace
{

    /// This class builds Dynamic Anonymous Classes

    public class DynamicTypeBuilderTest
    {    
        ///   
        /// Create instance based on any Source class as example based on PersonalData
        ///
        public static object CreateAnonymousDynamicInstance(PersonalData personalData, Type dynamicType, List<ClassDescriptorKeyValue> classDescriptionList)
        {
            var obj = Activator.CreateInstance(dynamicType);

            var propInfos = dynamicType.GetProperties();

            classDescriptionList.ForEach(x => SetValueToProperty(obj, propInfos, personalData, x));

            return obj;
        }

        private static void SetValueToProperty(object obj, PropertyInfo[] propInfos, PersonalData aisMessage, ClassDescriptorKeyValue description)
        {
            propInfos.SingleOrDefault(x => x.Name == description.Name)?.SetValue(obj, description.ValueGetter(aisMessage), null);
        }

        public static dynamic CreateAnonymousDynamicType(string entityName, List<ClassDescriptorKeyValue> classDescriptionList)
        {
            AssemblyName asmName = new AssemblyName();
            asmName.Name = $"{entityName}Assembly";
            AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);

            ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule($"{asmName.Name}Module");

            TypeBuilder typeBuilder = moduleBuilder.DefineType($"{entityName}Dynamic", TypeAttributes.Public);

            classDescriptionList.ForEach(x => CreateDynamicProperty(typeBuilder, x));

            return typeBuilder.CreateTypeInfo().AsType();
        }

        private static void CreateDynamicProperty(TypeBuilder typeBuilder, ClassDescriptorKeyValue description)
        {
            CreateDynamicProperty(typeBuilder, description.Name, description.Type);
        }

        ///
        ///Creation Dynamic property (from MSDN) with some Magic
        ///
        public static void CreateDynamicProperty(TypeBuilder typeBuilder, string name, Type propType)
        {
            FieldBuilder fieldBuider = typeBuilder.DefineField($"{name.ToLower()}Field",
                                                            propType,
                                                            FieldAttributes.Private);

            PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(name,
                                                             PropertyAttributes.HasDefault,
                                                             propType,
                                                             null);

            MethodAttributes getSetAttr =
                MethodAttributes.Public | MethodAttributes.SpecialName |
                    MethodAttributes.HideBySig;

            MethodBuilder methodGetBuilder =
                typeBuilder.DefineMethod($"get_{name}",
                                           getSetAttr,
                                           propType,
                                           Type.EmptyTypes);

            ILGenerator methodGetIL = methodGetBuilder.GetILGenerator();

            methodGetIL.Emit(OpCodes.Ldarg_0);
            methodGetIL.Emit(OpCodes.Ldfld, fieldBuider);
            methodGetIL.Emit(OpCodes.Ret);

            MethodBuilder methodSetBuilder =
                typeBuilder.DefineMethod($"set_{name}",
                                           getSetAttr,
                                           null,
                                           new Type[] { propType });

            ILGenerator methodSetIL = methodSetBuilder.GetILGenerator();

            methodSetIL.Emit(OpCodes.Ldarg_0);
            methodSetIL.Emit(OpCodes.Ldarg_1);
            methodSetIL.Emit(OpCodes.Stfld, fieldBuider);
            methodSetIL.Emit(OpCodes.Ret);

            propertyBuilder.SetGetMethod(methodGetBuilder);
            propertyBuilder.SetSetMethod(methodSetBuilder);

        }

        public class ClassDescriptorKeyValue
        {
            public ClassDescriptorKeyValue(string name, Type type, Func<PersonalData, object> valueGetter)
            {
                Name = name;
                ValueGetter = valueGetter;
                Type = type;
            }

            public string Name;
            public Type Type;
            public Func<PersonalData, object> ValueGetter;
        }

        ///
        ///Your Custom class description based on any source class for example
        /// PersonalData
        public static IEnumerable<ClassDescriptorKeyValue> GetAnonymousClassDescription(bool includeAddress, bool includeFacebook)
        {
            yield return new ClassDescriptorKeyValue("Id", typeof(string), x => x.Id);
            yield return new ClassDescriptorKeyValue("Name", typeof(string), x => x.FirstName);
            yield return new ClassDescriptorKeyValue("Surname", typeof(string), x => x.LastName);
            yield return new ClassDescriptorKeyValue("Country", typeof(string), x => x.Country);
            yield return new ClassDescriptorKeyValue("Age", typeof(int?), x => x.Age);
            yield return new ClassDescriptorKeyValue("IsChild", typeof(bool), x => x.Age < 21);

            if (includeAddress)
                yield return new ClassDescriptorKeyValue("Address", typeof(string), x => x?.Contacts["Address"]);
            if (includeFacebook)
                yield return new ClassDescriptorKeyValue("Facebook", typeof(string), x => x?.Contacts["Facebook"]);
        }

        ///
        ///Source Data Class for example
        /// of cause you can use any other class
        public class PersonalData
        { 
            public int Id { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Country { get; set; }
            public int Age { get; set; }

            public Dictionary<string, string> Contacts { get; set; }
        }

    }
}

Es ist auch sehr einfach, DynamicTypeBuilder zu verwenden, Sie müssen nur ein paar Zeilen wie diese einfügen:

    public class ExampleOfUse
    {
        private readonly bool includeAddress;
        private readonly bool includeFacebook;
        private readonly dynamic dynamicType;
        private readonly List<ClassDescriptorKeyValue> classDiscriptionList;
        public ExampleOfUse(bool includeAddress = false, bool includeFacebook = false)
        {
            this.includeAddress = includeAddress;
            this.includeFacebook = includeFacebook;
            this.classDiscriptionList = DynamicTypeBuilderTest.GetAnonymousClassDescription(includeAddress, includeFacebook).ToList();
            this.dynamicType = DynamicTypeBuilderTest.CreateAnonymousDynamicType("VeryPrivateData", this.classDiscriptionList);
        }

        public object Map(PersonalData privateInfo)
        {
            object dynamicObject = DynamicTypeBuilderTest.CreateAnonymousDynamicInstance(privateInfo, this.dynamicType, classDiscriptionList);

            return dynamicObject;
        }

    }

Ich hoffe, dass dieser Codeschnipsel jemandem hilft =) Viel Spaß!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X