2009-04-14 13 views
8

पर एनम्स बनाना/संशोधित करना मैं एक प्रोग्राम बना रहा हूं जहां उपयोगकर्ता के पास अपनी कस्टम प्रॉपर्टी बनाने का विकल्प है जो अंततः PropertyGrid में प्रदर्शित होगा। अभी मैं कस्टम संपादकों के साथ गड़बड़ नहीं करना चाहता हूं, इसलिए मैं केवल आदिम प्रकार गुणों (string, int, double, DateTime, bool इत्यादि) की अनुमति दे रहा हूं) PropertyGrid पहले से ही संपादकों में बनाया गया है।रनटाइम

हालांकि, मैं उपयोगकर्ता को कई विकल्प गुण बनाने का विकल्प भी देना चाहता हूं जहां वे संभव मूल्यों की एक सूची परिभाषित कर सकते हैं जो बदले में PropertyGrid में ड्रॉप डाउन सूची के रूप में दिखाई देगा।

जब मैं अपने कोड में Enum हार्ड कोड कोड करता हूं तो संपत्ति ग्रिड स्वचालित रूप से उस ड्रॉप डाउन सूची के रूप में enum के गुण दिखाती है। लेकिन क्या मैं रनटाइम पर एक गणना बना और संशोधित कर सकता हूं ताकि उपयोगकर्ता एक और संपत्ति विकल्प जोड़ सके, और PropertyGrid पर वापस जाएं और ड्रॉप डाउन में अपना नया विकल्प देखें?

अद्यतन

को ध्यान में रखते Patricks टिप्पणी, मैं सोच रहा हूँ कि Enum रों इस मामले में जाने के लिए सही तरीके से नहीं कर रहे हैं। तो मैं PropertyGrid आइटम में ड्रॉप डाउन को पॉप्युलेट करने के लिए तारों की एक सूची का उपयोग कैसे कर सकता हूं? क्या एक कस्टम संपादक की आवश्यकता होगी?

उत्तर

5

उत्तर एक साधारण वर्ग में है: टाइप कनवर्टर। (और हाँ, enums यहाँ उपयुक्त नहीं हैं)।

चूंकि मेरे पास बहुत सारे विवरण नहीं हैं, इसलिए मुझे लगता है कि आपके पास प्रॉपर्टीग्रिड को चयनित ऑब्जेक्ट संपत्ति द्वारा लक्षित उदाहरण में "लिंक किया गया" है और यह कि आपका लक्ष्य उदाहरण ICustomTypeDescriptor लागू करता है ताकि आप गुण (यानी संपत्ति डिस्क्रिप्टर) जोड़ सकें क्रम। मुझे आपका डिज़ाइन नहीं पता लेकिन यदि आप ऐसा नहीं कर रहे हैं, तो मैं आपको सलाह देता हूं कि आप इसे देखें।

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

अब, टाइपकॉन्टर (या स्ट्रिंग कनवर्टर शायद इस उदाहरण में) से व्युत्पन्न एक नया कनवर्टर लिखें। स्ट्रिंग्स की सूची लौटने के लिए आपको संदर्भ प्राप्त करने के लिए GetStandardValues ​​को समर्थन देना होगा और GetStandardValues ​​ (इंस्टेंस प्रॉपर्टी और स्ट्रिंग्स की सूची तक पहुंचने के लिए संदर्भ पैरामीटर का उपयोग करें)। यह कनवर्टर आपके PropertyDescriptor द्वारा PropertyDescriptor.Converter प्रॉपर्टी के साथ प्रकाशित किया जाएगा।

मुझे आशा है कि यह बहुत अस्पष्ट नहीं है। यदि इस प्रक्रिया पर आपके पास कोई विशिष्ट प्रश्न है, तो बस मुझे बताएं।

+0

क्या आप उस समाधान के लिए नमूना कोड प्रदान कर सकते हैं – Cracker

0

आप अपने कोड का उपयोग कर कोड बना सकते हैं, फिर उसे एक अस्थायी पाठ फ़ाइल में सहेज सकते हैं, और उसके बाद इसका उपयोग कर सकते हैं। यह धीमा होगा क्योंकि इसमें एचडीडी का उपयोग करना शामिल है। मैं reflection में देखने की अनुशंसा करता हूं।

संपादित करें: मुझे अपनी पुस्तकों में से एक में एक आदर्श उदाहरण मिला, यह है (यह काफी लंबा है लेकिन यदि आप इसे वीएस में कॉपी करते हैं, तो यह अधिक समझ में आता है)।

namespace Programming_CSharp 
{ 
    using System; 
    using System.Diagnostics; 
    using System.IO; 
    using System.Reflection; 
    using System.Reflection.Emit; 
    using System.Threading; 

    // used to benchmark the looping approach 
    public class MyMath 
    { 
     // sum numbers with a loop 
     public int DoSumLooping(int initialVal) 
     { 
     int result = 0; 
     for(int i = 1;i <=initialVal;i++) 
     { 
      result += i; 
     } 
     return result; 
     } 
    } 

    // declare the interface 
    public interface IComputer 
    { 
     int ComputeSum(); 
    } 

    public class ReflectionTest 
    { 
     // the private method which emits the assembly 
     // using op codes 
     private Assembly EmitAssembly(int theValue) 
     { 
     // Create an assembly name 
     AssemblyName assemblyName = 
      new AssemblyName(); 
     assemblyName.Name = "DoSumAssembly"; 

     // Create a new assembly with one module 
     AssemblyBuilder newAssembly = 
      Thread.GetDomain().DefineDynamicAssembly(
      assemblyName, AssemblyBuilderAccess.Run); 
     ModuleBuilder newModule = 
      newAssembly.DefineDynamicModule("Sum"); 

     // Define a public class named "BruteForceSums " 
     // in the assembly. 
     TypeBuilder myType = 
      newModule.DefineType(
      "BruteForceSums", TypeAttributes.Public); 

     // Mark the class as implementing IComputer. 
     myType.AddInterfaceImplementation(
      typeof(IComputer)); 

     // Define a method on the type to call. Pass an 
     // array that defines the types of the parameters, 
     // the type of the return type, the name of the 
     // method, and the method attributes. 
     Type[] paramTypes = new Type[0]; 
     Type returnType = typeof(int); 
     MethodBuilder simpleMethod = 
      myType.DefineMethod(
      "ComputeSum", 
      MethodAttributes.Public | 
      MethodAttributes.Virtual, 
      returnType, 
      paramTypes); 

     // Get an ILGenerator. This is used 
     // to emit the IL that you want. 
     ILGenerator generator = 
      simpleMethod.GetILGenerator(); 

     // Emit the IL that you'd get if you 
     // compiled the code example 
     // and then ran ILDasm on the output. 

     // Push zero onto the stack. For each 'i' 
     // less than 'theValue', 
     // push 'i' onto the stack as a constant 
     // add the two values at the top of the stack. 
     // The sum is left on the stack. 
     generator.Emit(OpCodes.Ldc_I4, 0); 
     for (int i = 1; i <= theValue;i++) 
     { 
      generator.Emit(OpCodes.Ldc_I4, i); 
      generator.Emit(OpCodes.Add); 

     } 

     // return the value 
     generator.Emit(OpCodes.Ret); 

     //Encapsulate information about the method and 
     //provide access to the method's metadata 
     MethodInfo computeSumInfo = 
      typeof(IComputer).GetMethod("ComputeSum"); 

     // specify the method implementation. 
     // Pass in the MethodBuilder that was returned 
     // by calling DefineMethod and the methodInfo 
     // just created 
     myType.DefineMethodOverride(simpleMethod, computeSumInfo); 

     // Create the type. 
     myType.CreateType(); 
     return newAssembly; 
     } 

     // check if the interface is null 
     // if so, call Setup. 
     public double DoSum(int theValue) 
     { 
     if (theComputer == null) 
     { 
      GenerateCode(theValue); 
     } 

     // call the method through the interface 
     return (theComputer.ComputeSum()); 
     } 

     // emit the assembly, create an instance 
     // and get the interface 
     public void GenerateCode(int theValue) 
     { 
     Assembly theAssembly = EmitAssembly(theValue); 
     theComputer = (IComputer) 
      theAssembly.CreateInstance("BruteForceSums"); 
     } 

     // private member data 
     IComputer theComputer = null; 

    } 

    public class TestDriver 
    { 
     public static void Main() 
     { 
     const int val = 2000; // Note 2,000 

     // 1 million iterations! 
     const int iterations = 1000000; 
     double result = 0; 

     // run the benchmark 
     MyMath m = new MyMath(); 
     DateTime startTime = DateTime.Now;    
     for (int i = 0;i < iterations;i++) 
      result = m.DoSumLooping(val); 
     } 
     TimeSpan elapsed = 
      DateTime.Now - startTime; 
     Console.WriteLine(
      "Sum of ({0}) = {1}",val, result); 
     Console.WriteLine(
      "Looping. Elapsed milliseconds: " + 
      elapsed.TotalMilliseconds + 
      " for {0} iterations", iterations); 

     // run our reflection alternative 
     ReflectionTest t = new ReflectionTest(); 

     startTime = DateTime.Now; 
     for (int i = 0;i < iterations;i++) 
     { 
      result = t.DoSum(val); 
     } 

     elapsed = DateTime.Now - startTime; 
     Console.WriteLine(
      "Sum of ({0}) = {1}",val, result); 
     Console.WriteLine(
      "Brute Force. Elapsed milliseconds: " + 
      elapsed.TotalMilliseconds + 
      " for {0} iterations", iterations); 
     } 
    } 
} 

आउटपुट: (2000) = 2001000
लूपिंग की योग। विलुप्त मिलीसेकंड:
11400.75 1000000 पुनरावृत्तियों के लिए
(2000) = 2001000
ब्रूट फोर्स का योग। बीत चुके मिलीसेकंड: यदि आप अधिक जानकारी चाहते हैं
406.25 1000000 के लिए पुनरावृत्तियों

Here पूरा अध्याय करने के लिए एक कड़ी है।

+1

जब लोग लोग बिना किसी त्रुटि के जवाब देते हैं तो मुझे वास्तव में नफरत है। क्या यह काम नहीं करता है? क्या यह सवाल का जवाब नहीं देता है? – Tarynn

-7

आप मूल्यों को पुनः प्राप्त करने के लिए Enum.GetNames() और Enum.GetValues ​​() का उपयोग कर सकते हैं और गतिशील रूप से उन्हें नए जोड़ सकते हैं। हालांकि मैं सुझाव देता हूं कि आप enum की बजाय किसी सूची का उपयोग करें या अपने डिज़ाइन पर पुनर्विचार करें। कुछ सही गंध नहीं करता है।

+2

उह, नहीं, आप नहीं कर सकते। – Samuel

+0

क्या हम उन्हें प्रतिबिंब के माध्यम से जोड़ सकते हैं? –

+0

GETNames और GETValues ​​आपको एक संकेत देना चाहिए कि आप उस विधियों के साथ enum को नहीं बदल सकते हैं ... –

3

आपकी समस्या का सामान्य इंजीनियरिंग समाधान आपके डेटाबेस में संदर्भ डेटा के रूप में सूची को बनाए रखने के लिए उपयोग करना है। सामान्य enums में संकलन समय पर परिभाषित स्थिरांक होने का इरादा है, और कोड के बाद में जारी किए गए उनके संशोधन को हतोत्साहित किया जाता है (अकेले रनटाइम दें), क्योंकि यह स्विच स्टेटमेंट में साइड इफेक्ट्स का कारण बन सकता है।