नए बेनामी वर्ग को कैसे गतिशील करें?


95

C # 3.0 में आप निम्न सिंटैक्स के साथ अनाम वर्ग बना सकते हैं

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

क्या इन अनाम वर्ग को एक चर में गतिशील बनाने का एक तरीका है?


उदाहरण:

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

गतिशील बनाएँ उदाहरण:

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

Beacuse मुझे करने की आवश्यकता है:

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

और दृश्य 1:

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

अगर मैं फोन करूँ:

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

यह परिणाम नहीं दिखा सकता है:

Name = 123

और यह भी कि मैं कैसे AnonymouseType के लिए ExpandoObject कन्वर्ट करने के लिए?

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

अंतिम, मैं 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));
    } 
  }
}

डायनामिकन्यूनेम विधि कैसे लागू करें या ShowPropertiesValue () को कैसे संशोधित करें?

मेरी प्रेरणाएँ हैं:

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

अगर मैं डायनेमिकऑब्जेक्ट के गेट टाइप विधि को हुक कर सकता हूं, और कंपाइल को दृढ़ता से टाइप किए गए प्रकार में परिवर्तित कर सकता है। उपरोक्त सीमलेस कोड ठीक काम कर सकता है।


@ व्लाद: मैं मानता हूँ कि मैं प्रेरणाओं के बारे में थोड़ा अस्पष्ट हूँ।
स्टीवन सुदित

@VladLazarenko मुझे लगता है कि आप सही हैं :-)
oberfreak 19

कृपया हमें बताएं, आप क्या करना चाहते हैं और यह आपका चयनित समाधान क्यों है।
oberfreak

ExpandoObject, नहीं ExpandObject (जोड़ा 'ओ')।
N0thing

@StevenSudit यह लेख एक या दूसरे का उपयोग करने की आपकी प्रेरणा का पता लगाने में मदद कर सकता है: blogs.msdn.com/b/csharpfaq/archive/2010/01/25/…
juagicre

जवाबों:


75

बेनामी प्रकार केवल नियमित प्रकार होते हैं जिन्हें स्पष्ट रूप से घोषित किया जाता है। उनके पास करने के लिए बहुत कम है dynamic

अब, यदि आप एक ExpandoObject का उपयोग करते हैं और इसे एक dynamicचर के माध्यम से संदर्भित करते हैं , तो आप मक्खी पर फ़ील्ड जोड़ या हटा सकते हैं।

संपादित करें

सुनिश्चित करें कि आप कर सकते हैं: बस इसे कास्ट करें IDictionary<string, object>। तब आप अनुक्रमणिका का उपयोग कर सकते हैं।

आप एक ही कास्टिंग तकनीक का उपयोग खेतों पर पुनरावृति करने के लिए करते हैं:

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

उपरोक्त कोड और बहुत कुछ उस लिंक पर क्लिक करके पाया जा सकता है।


1
लेकिन एक्सपोऑबजेक्ट इसे नहीं कर सकता:dynamic o1 = new ExpandObject(); o1."ID" = 1; o1."Name" = "Foo";
फ्लैश

लेकिन यह भी नहीं कर सकता है: टाइप करें o1Type = o1.GetType (); var प्रॉप्स = o1Type.GetProperties (); प्रॉप्स खाली है
फ्लैश

3
आप बस इतना ही कह रहे हैं कि गतिशील गुण दृढ़ता से टाइप किए गए गुणों के समान नहीं हैं। यह तुच्छ रूप से सत्य है।
स्टीवन सुदित

4
stackoverflow.com/a/4024786/998793 से पता चलता है कि यह एक सामान्य शब्दकोष में कैसे डाला जाए ((IDictionary<string, object>)o1).Add("Name", "Foo");:। आप कर सकते हैं तो पहुँच के रूप मेंo1.Name
rogersillito

15

आप इस तरह से एक ExpandoObject बना सकते हैं:

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

और इसे डायनामिक करने के बाद, वे मान गुण जैसे दिखेंगे:

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

हालांकि, वे वास्तविक गुण नहीं हैं और प्रतिबिंब का उपयोग करके पहुँचा नहीं जा सकता है। तो निम्न कथन एक अशक्त लौटेगा:

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

1

कारण यह संभव है कि बहुत ही कूल एक्सपेंडीओबजेक्ट क्लास का उपयोग करके गतिशील कक्षाएं बनाई जाएं। लेकिन हाल ही में मैंने प्रोजेक्ट पर काम किया और सामना किया कि एक्सप्लेनो ऑब्जेक्ट को एक साधारण एनॉनिमस वर्ग के रूप में एक्सएमएल पर एक ही प्रारूप में सीरियलाइज़ नहीं किया गया है, यह दया थी (=, यही कारण है कि मैंने अपनी खुद की क्लास बनाने और इसे आपके साथ साझा करने का निर्णय लिया है। प्रतिबिंब और गतिशील निर्देश, असेंबली, क्लास और इंस्टेंस को वास्तव में गतिशील रूप से बनाता है। आप अपनी कक्षा में शामिल संपत्तियों को जोड़ सकते हैं, हटा सकते हैं और बदल सकते हैं। यह है:

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

    }
}

डायनामिक टाइपब्युलेर का उपयोग करना भी बहुत सरल है, आपको बस इस तरह से कुछ लाइनें डालने की आवश्यकता है:

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

    }

मुझे उम्मीद है कि यह कोड स्निपेट किसी की मदद करेगा =) आनंद लें!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.