2010-03-01 8 views
10

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

सी एपीआई इस तरह कुछ दिखता है, और जेनरेट कोड मेरी लाइब्रेरी के निचले स्तर के हिस्से के माध्यम से इसका उपयोग करेगा जो P/C Lua C लाइब्रेरी को आमंत्रित करता है।

static int foo (lua_State *L) 
{ 
    int n = lua_gettop(L); /* number of arguments */ 
    lua_Number sum = 0; 
    int i; 
    for (i = 1; i <= n; i++) 
    { 
     if (!lua_isnumber(L, i)) 
     { 
      lua_pushstring(L, "incorrect argument"); 
      lua_error(L); 
     } 
     sum += lua_tonumber(L, i); 
    } 
    lua_pushnumber(L, sum/n);  /* first result */ 
    lua_pushnumber(L, sum);   /* second result */ 
    return 2;     /* number of results */ 
} 

तो मूल रूप से विचार एक सी # विधि एक विधि से ऊपर की तरह लुआ एपीआई का उपयोग करता है उन पैरामीटर भेजने और उन वापसी प्रकार वापस जाने के लिए लेने के लिए, अपने मानकों को प्रतिबिंबित और मान, उत्पन्न (या कैश से प्राप्त करें) है और आखिरकार उस विधि को लुआ को दबाएं। तो जब सी # फ़ंक्शन को लुआ से बुलाया जाता है तो यह लुआ -> जादू रैपर फ़ंक्शन -> सामान्य सी # फ़ंक्शन जैसा दिखता है।

धन्यवाद।

उत्तर

14

तो मैं समझता हूँ कि आप क्या चाहते हैं, ऐसा लगता है आप 2 विकल्प हैं:

  1. use the CodeDOM उत्पन्न करने के लिए और गतिशील, कोड संकलन रनटाइम पर।
  2. वास्तविक सी # स्रोत कोड उत्सर्जित करें, और गतिशील रूप से इसे रनटाइम पर एक कॉल करने योग्य असेंबली में संकलित करें।

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

CodeDOM इस तरह दिखता है:

System.Type mt= a[0].GetType(); 

System.CodeDom.CodeTypeDeclaration class1 = new System.CodeDom.CodeTypeDeclaration(mt.Name); 
class1.IsClass=true; 
class1.TypeAttributes = System.Reflection.TypeAttributes.Public; 
class1.Comments.Add(new System.CodeDom.CodeCommentStatement("Wrapper class for " + mt.Name)); 

System.CodeDom.CodeConstructor ctor; 
ctor= new System.CodeDom.CodeConstructor(); 
ctor.Attributes = System.CodeDom.MemberAttributes.Public; 
ctor.Comments.Add(new System.CodeDom.CodeCommentStatement("the null constructor")); 
class1.Members.Add(ctor); 
ctor.Statements.Add(new System.CodeDom.CodeAssignStatement(new System.CodeDom.CodeVariableReferenceExpression("m_wrapped"), new System.CodeDom.CodeObjectCreateExpression(mt))); 

ctor= new System.CodeDom.CodeConstructor(); 
ctor.Attributes = System.CodeDom.MemberAttributes.Public; 
ctor.Comments.Add(new System.CodeDom.CodeCommentStatement("the 'copy' constructor")); 
class1.Members.Add(ctor); 
ctor.Parameters.Add(new System.CodeDom.CodeParameterDeclarationExpression(mt,"X")); 
ctor.Statements.Add(new System.CodeDom.CodeAssignStatement(new System.CodeDom.CodeVariableReferenceExpression("m_wrapped"), new System.CodeDom.CodeVariableReferenceExpression("X"))); 

// embed a local (private) copy of the wrapped type 
System.CodeDom.CodeMemberField field1; 
field1= new System.CodeDom.CodeMemberField(); 
field1.Attributes = System.CodeDom.MemberAttributes.Private; 
field1.Name= "m_wrapped"; 
field1.Type=new System.CodeDom.CodeTypeReference(mt); 
class1.Members.Add(field1); 

... 

उस पर चला जाता है। और इसपर। जैसा कि आप देख सकते हैं, यह बहुत बदसूरत हो जाता है।फिर बाद में आप इसे संकलित करते हैं, जिसे मैंने नहीं दिखाया। मुझे लगता है कि आप इस दृष्टिकोण को नहीं लेना चाहते हैं।


मुझे कोडडॉम का उपयोग करने के लिए बहुत क्रूरता मिली; इसके बजाय, अब जब मुझे गतिशील रूप से जेनरेट की गई असेंबली की आवश्यकता होती है, तो मैं वास्तविक सी # कोड उत्सर्जित करता हूं, आमतौर पर टेम्पलेट्स के माध्यम से, स्मृति में एक स्ट्रिंग में, और संकलित करता हूं। यह मेरे उद्देश्यों के लिए बहुत आसान है। संकलन इस तरह दिखता है:

var cp = new System.CodeDom.Compiler.CompilerParameters { 
    ReferencedAssemblies.Add(filesystemLocation), // like /R: option on csc.exe 
    GenerateInMemory = true, // you will get a System.Reflection.Assembly back 
    GenerateExecutable = false, // Dll 
    IncludeDebugInformation = false, 
    CompilerOptions = "" 
}; 

var csharp = new Microsoft.CSharp.CSharpCodeProvider(); 

// this actually runs csc.exe: 
System.CodeDom.Compiler.CompilerResults cr = 
     csharp.CompileAssemblyFromSource(cp, LiteralSource); 


// cr.Output contains the output from the command 

if (cr.Errors.Count != 0) 
{ 
    // handle errors 
} 

System.Reflection.Assembly a = cr.CompiledAssembly; 

// party on the type here, either via reflection... 
System.Type t = a.GetType("TheDynamicallyGeneratedType"); 

// or via a wellknown interface 

उपरोक्त कोड में, LiteralSource स्रोत कोड संकलित की हैं। जैसा कि मैंने कहा, मैं इसे एक टेम्पलेट पढ़ने और रिक्त स्थान भरकर उत्पन्न करता हूं।

+0

यह एक दिलचस्प दृष्टिकोण है, मैंने कभी भी वास्तविक सी # लिखने के बारे में सोचा नहीं था। शायद मैं क्या करूँगा। धन्यवाद। – jsimmons

+0

आप डिस्क पर कक्षाओं को पहली जगह कैसे बनाते हैं? – jcolebrand

+0

@jcolebrand - मैं स्पष्ट नहीं हूं कि आप क्या पूछ रहे हैं, लेकिन मुझे लगता है कि आपको एक नया प्रश्न पोस्ट करना चाहिए। – Cheeso

0

आप अपने सी # को COM के रूप में बेनकाब कर सकते हैं, जो सभी (सार्वजनिक) विधियों को बाहरी ऐप्स कहलाए जाने की अनुमति देगा।

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

+0

इस तरह के प्रतिबिंब का उपयोग करना काफी कुछ है जो मैं करना चाहता था। – jsimmons

1

मुझे यकीन नहीं है कि मैं आपके प्रश्न को सही तरीके से व्याख्या कर रहा हूं लेकिन आप Castle.Dynamic प्रॉक्सी पर एक नज़र रखना चाहते हैं। यह आपको कक्षाओं और इंटरफेस के लिए प्रॉक्सी बनाने की अनुमति देता है और फिर कुछ विधि कॉल (इंटरफ़ेस पर कुछ भी और वास्तविक कक्षा पर वर्चुअल कुछ भी) को रोकता है। जब आप कॉल को रोकते हैं तो आप केवल तर्कों को देख सकते हैं और पी-इनवॉक के माध्यम से लू एपीआई को कॉल अग्रेषित कर सकते हैं। एक महान ट्यूटोरियल here है।

+0

यह दिलचस्प है, मैं निश्चित रूप से उसमें देख लूंगा। मुझे लगता है कि सी # से लुआ विधियों को कॉल करने के लिए और अधिक उपयोगी होगा जहां मैं लुआ से सी # विधियों को कॉल करना चाहता हूं। – jsimmons

0

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

+0

यह एलयूए (या किसी भी भाषा) से रन टाइम पर गतिशील रूप से एक मनमानी सी # फ़ंक्शन को कॉल करने में सक्षम होने का पता नहीं लगाता है –

+0

आप रैपर वर्ग उत्पन्न करने के लिए टी 4 का उपयोग कर सकते हैं और आखिरकार उसी परिणाम को प्राप्त कर सकते हैं क्योंकि आप स्वीकृत उत्तर में कोडडॉम का उपयोग करेंगे। यह लुआ को गतिशील रूप से किसी भी मनमाना तरीके से कॉल करने में सक्षम बनाने के बारे में नहीं है। तो मैं आपकी चिंता और डाउन-वोटिंग को समझ नहीं पा रहा हूं! –

+0

"... मुझे इन परंपराओं का पालन किए बिना मनमानी सी # विधियों को कॉल करने में सक्षम होने में दिलचस्पी है ..." –

संबंधित मुद्दे