Yeni Anonim Sınıf nasıl dinamik hale getirilir?


95

C # 3.0'da aşağıdaki sözdizimi ile anonim sınıf oluşturabilirsiniz

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

Bu anonim sınıfı bir değişkene dinamik oluşturmanın bir yolu var mı?


Misal:

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

Dinamik oluşturma Örneği:

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

Çünkü yapmam gerek:

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

Ve Scene1:

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

ararsam:

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

Sonucu gösteremez:

Name = 123

Ayrıca ExpandoObject'i AnonymouseType'a nasıl dönüştürebilirim?

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

Son olarak, ShowPropertiesValue () yöntemini değiştiriyorum

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));
    } 
  }
}

DynamicNewAnonymous yöntemi nasıl uygulanır veya ShowPropertiesValue () nasıl değiştirilir?

Benim motivasyonum:

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

DynamicObject'in GetType Yöntemini bağlayabilirsem ve Compel, kesin olarak yazılmış Türe dönüştürebilir. Yukarıdaki Kesintisiz kod iyi çalışabilir.


@Vlad: Motivasyonlar konusunda biraz kararsız olduğumu kabul ediyorum.
Steven Sudit

@VladLazarenko Sanırım haklısın :-)
oberfreak

Lütfen bize ne yapmak istediğinizi ve neden bunun sizin seçtiğiniz çözüm olduğunu söyleyin.
oberfreak

ExpandoObject, ExpandObject değil ('o' eklendi).
N0thing

@StevenSudit Bu makale, birini veya diğerini kullanma motivasyonunuzu bulmanıza yardımcı olabilir: blogs.msdn.com/b/csharpfaq/archive/2010/01/25/…
juagicre

Yanıtlar:


75

Anonim türler, örtük olarak bildirilen normal türlerdir. Yapacakları çok az şey var dynamic.

Şimdi, bir ExpandoObject kullanırsanız ve ona bir dynamicdeğişken aracılığıyla başvurursanız , anında alan ekleyebilir veya kaldırabilirsiniz.

Düzenle

Elbette yapabilirsiniz: sadece yayınlayın IDictionary<string, object>. Ardından indeksleyiciyi kullanabilirsiniz.

Alanlar üzerinde yineleme yapmak için aynı döküm tekniğini kullanırsınız:

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

Yukarıdaki kod ve daha fazlası bu bağlantıya tıklayarak bulunabilir.


1
Ancak ExpandoObject bunu yapamaz:dynamic o1 = new ExpandObject(); o1."ID" = 1; o1."Name" = "Foo";
Flaş

Ama bunu da yapamaz: o1Type = o1.GetType () yazın; var props = o1Type.GetProperties (); sahne boş
Flash

3
Tek yaptığınız, dinamik özelliklerin türü kesin belirlenmiş özelliklerle aynı olmadığını söylemektir. Bu önemsiz şekilde doğrudur.
Steven Sudit

4
stackoverflow.com/a/4024786/998793 gösterileri nasıl bir jenerik sözlüğe döküm ederek bunu: ((IDictionary<string, object>)o1).Add("Name", "Foo");. Daha sonrao1.Name
rogersillito

15

Bunun gibi bir ExpandoObject oluşturabilirsiniz:

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

Ve onu dinamiğe dönüştürdükten sonra, bu değerler özelliklere benzeyecek:

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

Ancak, bunlar gerçek mülkler değildir ve Yansıma kullanılarak erişilemez. Dolayısıyla, aşağıdaki ifade bir boş döndürür:

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

2

Çünkü çok havalı ExpandoObject sınıfını kullanarak dinamik sınıflar oluşturmak mümkündür. Ancak son zamanlarda proje üzerinde çalıştım ve Expando Object'in xml üzerinde basit bir Anonim sınıfla aynı formatta olmayacağıyla karşı karşıya kaldım, pity = idi (bu yüzden kendi sınıfımı oluşturmaya ve sizinle paylaşmaya karar verdim. yansıma ve dinamik yönerge, Assembly, Class ve Instance'ı gerçekten dinamik olarak oluşturur.Sınıfınıza dahil olan özellikleri anında ekleyebilir, kaldırabilir ve değiştirebilirsiniz İşte burada:

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; }
        }

    }
}

DynamicTypeBuilder'ı kullanmak da çok basit, sadece aşağıdaki gibi birkaç satır koymanız gerekiyor:

    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;
        }

    }

Umarım bu kod parçacığı birine yardımcı olur =) Keyfini çıkarın!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.