2009-07-03 18 views
6

पर गतिशील रूप से फ़ंक्शन बनाना संभवतः ऐसा करना भी संभव नहीं है, लेकिन मैं वैसे भी पूछूंगा। क्या कोई ऐसा फ़ंक्शन बनाना संभव है जो एक स्ट्रिंग प्राप्त करता है और फिर इसे लैम्ब्डा में प्रयुक्त ऑपरेटर (=>) के लिए दाएं तरफ तर्क के रूप में उपयोग करता है?रन-टाइम

वास्तव में, मुझे क्या करना चाहते हैं रनटाइम के दौरान एक विशिष्ट वर्ग की एक विशेष विधि को फिर से परिभाषित करने के लिए सक्षम होने के लिए है। मैं प्रोग्राम के साथ एक समारोह लिखना चाहता हूं और इसे एक प्रतिनिधि को जोड़ रहा हूं। क्या यह संभव है?

+0

क्या आप हमें बता सकते हैं कि आपका वास्तविक उपयोग केस क्या है? हो सकता है कि आपकी आवश्यकता को पूरा करने का कोई और तरीका हो। – SolutionYogi

+0

अगर मैं इसे सही ढंग से पढ़ रहा हूं, तो आप एक स्ट्रिंग को eval() करना चाहते हैं? http://en.wikipedia.org/wiki/Eval – Stobor

उत्तर

8

ऐसा करने का सबसे आसान तरीका शायद टीसीके के सुझाव के रूप में DLINQ है।

सबसे तेज़ (मुझे विश्वास है, 3.5 में) DynamicMethod बनाना है। यह भी सबसे डरावनी विधि है। आप अनिवार्य रूप से आईएल का उपयोग कर एक विधि बना रहे हैं, जो मशीन भाषा में कोड लिखने के समान महसूस करता है।

मैं यह करने के गतिशील रूप से कुछ बात या किसी अन्य रूप में ईवेंट हैंडलर्स संलग्न करने के लिए की जरूरत है (अच्छी तरह से, मैं यह सब करने की ज़रूरत नहीं किया था, मैं सिर्फ इकाई परीक्षण घटनाओं आसान बनाना चाहते थे)। उस समय मुझे थोड़ा मुश्किल लग रहा था क्योंकि मुझे आईएल के बारे में बकवास नहीं पता था, लेकिन मुझे इसे पूरा करने का एक आसान तरीका पता चला।

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

गतिशील तरीकों, एक बार का निर्माण किया, संकलित तरीके के रूप में लगभग उसी गति पर आह्वान (एक परीक्षण जहां गतिशील तरीकों ~ 20ms में कहा जा सकता है जहां प्रतिबिंब 200 मि.से पदभार संभाल लिया देखा था)।

+0

वाह, और यहां मैंने सोचा कि मुझे .NET के बारे में कुछ पता था। और मैंने कभी इसके बारे में नहीं सुना। मुझे यह पूछने से डर है कि आपने कभी इस तरह की सुविधा पर कैसे ठोकर खाई। –

+0

2.0 – flq

5

आपका प्रश्न बहुत स्पष्ट नहीं है, लेकिन आप निश्चित रूप से अभिव्यक्ति के पेड़ का उपयोग प्रतिनिधियों निष्पादन समय पर गतिशील बनाने के लिए कर सकते हैं। (ऐसे CodeDOM के रूप में यह कर के अन्य तरीके हैं, लेकिन अभिव्यक्ति के पेड़ handier वे सभी की जरूरत करना अगर कर रहे हैं। आप क्या कर सकते करने के लिए महत्वपूर्ण प्रतिबंध रहे हैं लेकिन,।)

यह अक्सर एक लैम्ब्डा उपयोग करना आसान हो यद्यपि कुछ कब्जे वाले चर के साथ अभिव्यक्ति।

उदाहरण के लिए, एक समारोह है जो किसी भी पूर्णांक तक निर्धारित राशि जोड़ देगा बनाने के लिए, आप लिख सकते हैं:

static Func<int, int> CreateAdder(int amountToAdd) 
{ 
    return x => x + amountToAdd; 
} 

... 
var adder = CreateAdder(10); 
Console.WriteLine(adder(5)); // Prints 15 

यदि यह मदद नहीं करता है, अपने प्रश्न को स्पष्ट करें।

8

आप इसे कैसे करना है के कई तरीके हैं:

  • गतिशील लैम्ब्डा अभिव्यक्ति बनाने (Dynamic LINQ: Part 1 को देखो)
  • गतिशील CodeDom मॉडल बनाने और रन-टाइम में यह संकलन (CodeDom.Compiler namespace
  • गतिशील देखो सी #/वीबी.नेट स्रोत कोड बनाएं और इसे रन-टाइम पर संकलित करें (CSharpCodeProvider और VBCodeProvider कक्षाएं देखें)
  • डायनामिक रूप से ऑब्जेक्ट मॉडल बनाएं, जो विधि की तरह ही काम कर सकता है (देखें Strategy Design Pattern
+0

मेरी इच्छा है कि मैं दोनों उत्तरों को सही के रूप में चुन सकूं। दोनों मुझे बहुत अच्छे समाधान प्रदान करते हैं। और यहां मैंने सोचा कि यह असंभव होगा। अब, रणनीति पैटर्न वह नहीं है जिसे मैं ढूंढ रहा था। रणनीति का उपयोग करने के लिए, मुझे विधियों को लागू करना होगा ताकि मैं उन्हें स्वैप कर सकूं। –

3
नहीं

है कि मैं अन्य बेहतर विकल्पों पर इस सिफारिश कर रहा हूँ, लेकिन वहाँ एक 7 वें विधि है और thats AssemblyBuilder, ModuleBuilder, TypeBuilder, और MethodBuilderSystem.Reflection.Emit नाम स्थान में उपयोग करने के लिए एक गतिशील विधानसभा बनाने के लिए। DynamicMethod का उपयोग करने के समान यह वही वूडू है।

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

आप यहाँ शुरू कर दिया कुछ कोड है प्राप्त करने के लिए ...

using System; 
using System.Reflection; 
using System.Reflection.Emit; 

var myAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
     new AssemblyName("Test"), AssemblyBuilderAccess.RunAndSave); 
var myModule = myAssembly.DefineDynamicModule("Test.dll"); 
var myType = myModule.DefineType("ProxyType", TypeAttributes.Public | TypeAttributes.Class, 
         typeof(TypeToSeverelyModifyInAnUglyWayButItsNecessary)); 
var myMethod = myType.DefineMethod("MethodNameToOverride", 
         MethodAttributes.HideBySig | MethodAttributes.Public, 
         typeof(void),Type.EmptyTypes); 
var myIlGenerator = myMethod.GetILGenerator(); 
myIlGenerator.Emit(OpCodes.Ret); 
var type = myType.CreateType(); 
+0

के बाद से डायनामिक मोड उपलब्ध है, ऐसा लगता है कि डायनेमिक मोड का उपयोग करने से कोड के समान मात्रा में ऐसा लगता है। क्या डायनामिक मोड में इसका उपयोग करने का कोई कारण है? यदि विल सही है, तो डायनामिक मोड्स संकलित कोड के रूप में लगभग तेज़ होते हैं (भले ही 20ms कंप्यूटर समय में अनंत काल है)। –

+0

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

0

आप वर्चुअल रूप में प्रणाली की घोषणा हैं, तो आप अन्य से एक के साथ स्थानापन्न करने के लिए एक गतिशील रूप से निर्मित (महल के DynamicProxy उपयोग करने के लिए सक्षम हो सकता है उत्तर के तरीकों) रनटाइम पर कार्यान्वयन:

कैसल डायनामिकप्रॉक्सी रनटाइम पर फ्लाई पर हल्के वजन वाले .NET प्रॉक्सी उत्पन्न करने के लिए एक लाइब्रेरी है। प्रॉक्सी ऑब्जेक्ट्स किसी ऑब्जेक्ट के सदस्यों को क्लास के कोड को संशोधित किए बिना अवरुद्ध करने की अनुमति देता है। दोनों वर्गों और इंटरफेस को प्रॉक्सी किया जा सकता है, हालांकि केवल वर्चुअल सदस्यों को अवरुद्ध किया जा सकता है।

+0

मैं अपने तीसरे पक्ष के पुस्तकालयों का उपयोग करने से बचने के लिए उत्सुक हूं कोड। यह विक्रेता लॉक-इन समस्या से बचने के लिए है। जब मैंने डेल्फी में कोड किया था तब मुझे इससे पहले गंभीर समस्याएं थीं। उदाहरण के लिए, मैंने अभी SQLite का उपयोग करने से स्विच किया है - भले ही मुझे यह बहुत पसंद है - SQLServer CE को केवल फ्रेमवर्क के भीतर पूरी तरह से रहने के लिए। –

+2

इसका खुला स्रोत होने का लाभ होता है, इसलिए आप एक वाणिज्यिक समाधान के साथ "लॉक इन" नहीं हैं। कभी-कभी आपको पहिया बनाम वास्तव में चीजों को पूरा करने के फायदे का वजन करना पड़ता है। – Jacob

0

अपने प्रश्न में दूसरा पैराग्राफ पता चलता है कि वास्तव में क्या आप के बाद हो सकता है सीधा IOC (नियंत्रण के उलट)

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

+0

नहीं, यह नहीं है। मैं जो चाहता हूं वह रनटाइम के दौरान कक्षा के किसी तरीके को संशोधित करने में सक्षम होना है जिसे मैं रनटाइम में टाइप कर रहा हूं। बहुत कुछ एक eval के समान, सिवाय इसके कि मैं बस इसे eval और मरना नहीं चाहता। मैं इसे एक प्रतिनिधि से जुड़ा रहना चाहता हूं जब तक कि मुझे इसे फिर से बदलने की आवश्यकता न हो। –

+0

आह, ठीक है, तो आपके ऐप में एक टेक्स्ट इनपुट हो सकता है जो आपको किसी फ़ंक्शन की क्रिया को संशोधित करने के लिए कुछ कोड दर्ज करने देता है? –

1

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

+0

मैं 100% सहमत हूं, यह पहली पसंद होनी चाहिए। – Jake