2010-11-15 20 views
18

में संग्रहीत किया गया है क्या यह फ़ंक्शन को कॉल करना संभव है जिसका नाम डेल्फी में स्ट्रिंग में संग्रहीत है?डेल्फी: किसी फ़ंक्शन को कॉल करें जिसका नाम स्ट्रिंग

+5

के लिए इस की जरूरत है अगर ऐसा है, यह अभी भी एक बुरा विचार है। तुम्हें क्या करने की ज़रूरत है? – delnan

+1

@ डेलनन यह एक बुरा विचार क्यों है? मैं कोशिश कर रहा हूं, उदाहरण के लिए, मेनू कमांड के रूप में कुछ गतिशील रूप से बनाए गए बटन को लागू करने के लिए। प्रत्येक के लिए कॉल करने के लिए कार्यों को डीबी से खींचा जाता है और एक सरणी में डाल दिया जाता है। फिर मैं उस प्रक्रिया को कॉल करता हूं जिसका नाम सरणी तत्व में होता है, जब कोई विशेष बटन क्लिक किया जाता है। मुझे लगता है कि यह अच्छा है। यह एक बुरा विचार क्यों है? मैं वास्तव में लाजर पास्कल (डेल्फी के समान) पर कोशिश कर रहा हूं – itsols

+0

@itsols विभिन्न तकनीकी मुद्दों के अलावा (जो * महत्वपूर्ण हैं, लेकिन व्याख्या करने के लिए जगह लेते हैं और हमेशा * लागू नहीं होते हैं), मुख्य आपत्ति यह है कि आवेदन डेटा के साथ चर नामों को भ्रमित करता है। नेड बचेचेल्डर ने ऐसी भाषा के संदर्भ में इसी तरह के भ्रम पर लिखा है, जहां यह वास्तव में करना आसान है: [अपने चर नामों से डेटा रखें] (http://nedbatchelder.com/blog/201112/keep_data_out_of_your_variable_names.html)। प्रथम श्रेणी के कार्यों के साथ-साथ मैपिंग डेटा संरचना या 'केस' कथन का उपयोग करके, आप दोनों को भ्रमित किए बिना एक ही चीज़ प्राप्त कर सकते हैं। – delnan

उत्तर

21

कृपया आप जो हासिल करने की कोशिश कर रहे हैं, उसके बारे में अधिक जानकारी दें।

मैं जानता हूँ कि जहाँ तक:

  • ऐसा एक यादृच्छिक समारोह कॉल करने के लिए संभव नहीं है।
  • कक्षा और ऑब्जेक्ट फ़ंक्शंस (MyObject.Function) के लिए यह आरटीटीआई के साथ किया जा सकता है, लेकिन यह बहुत काम है।
  • यदि आपको केवल एक विशेष प्रकार के कार्यों को कॉल करने की आवश्यकता है (कहें, फ़ंक्शन (पूर्णांक, पूर्णांक): स्ट्रिंग), यह बहुत आसान है।

पिछले एक के लिए, एक समारोह प्रकार की घोषणा है, तो एक समारोह सूचक हो और इस तरह यह डाली:

type 
    TMyFuncType = function(a: integer; b: integer): string of object; 

    TMyClass = class 
    published 
    function Func1(a: integer; b: integer): string; 
    function Func2(a: integer; b: integer): string; 
    function Func3(a: integer; b: integer): string; 
    public 
    function Call(MethodName: string; a, b: integer): string; 
    end; 

function TMyClass.Call(MethodName: string; a, b: integer): string; 
var m: TMethod; 
begin 
    m.Code := Self.MethodAddress(MethodName); //find method code 
    m.Data := pointer(Self); //store pointer to object instance 
    Result := TMyFuncType(m)(a, b); 
end; 

{...} 

//use it like this 
var MyClass: TMyClass; 
begin 
    MyClass := TMyClass.Create; 
    MyClass.Call('Func1', 3, 5); 
    MyClass.Call('Func2', 6, 4); 
    MyClass.Destroy; 
end. 
+0

यह संभव होना चाहिए। यदि वीबी 6 ऐसा कर सकता है, निश्चित रूप से डेल्फी को इसकी अनुमति देनी चाहिए। विचार के लिए – itsols

7

यदि आप पूछ रहे हैं कि जावास्क्रिप्ट eval() कुछ ऐसा है जो डेल्फी में संभव है, तो डेल्फी देशी कोड में संकलित होने के बाद से यह आसानी से प्राप्त नहीं किया जा सकता है।

आप केवल कुछ तार आप हमेशा कर सकते हैं समर्थन करने के लिए की जरूरत है कई if या एक case ... कुछ की तरह:

if myString = 'myFunction' then 
    myFunction(); 
+0

मैंने इसे वीबी 6 में किया है और यह ** ** मूल-संकलित भाषा है। तो मुझे विश्वास है कि डेल्फी के साथ भी यह संभव होना चाहिए (और मेरे मामले में लाजर पास्कल) – itsols

5

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

वैकल्पिक रूप से, आप किसी तालिका में फ़ंक्शन पॉइंटर्स स्टोर कर सकते हैं, या यहां तक ​​कि TStringList की ऑब्जेक्ट प्रॉपर्टी भी संग्रहीत कर सकते हैं और स्ट्रिंग नाम से उन्हें प्रभावी रूप से इंडेक्स कर सकते हैं।

डेल्फी में नाम से फ़ंक्शन की सीधे कॉलिंग संभव नहीं है।

+1

यह वर्ग कार्यों के लिए है। आरटीटीआई भी उनके लिए संग्रहीत किया जा सकता है, यहां तक ​​कि पैरामीटर और कॉलिंग सम्मेलन के विवरण भी। लेकिन यह पिटा है। – himself

8

मैं कोई भी एक dispatch table सुझाव दिया है हैरान हूँ। यह वही है जो इसके लिए है।

program RPS; 

uses 
    SysUtils, 
    Generics.Collections; 

type 
    TDispatchTable = class(TDictionary<string, TProc>); 

procedure Rock; 
begin 
end; 

procedure Paper; 
begin 
end; 

procedure Scissors; 
begin 
end; 

var 
    DispatchTable: TDispatchTable; 

begin 
    DispatchTable := TDispatchTable.Create; 
    try 
    DispatchTable.Add('Rock', Rock); 
    DispatchTable.Add('Paper', Paper); 
    DispatchTable.Add('Scissors', Scissors); 

    DispatchTable['Rock'].Invoke; // or DispatchTable['Rock'](); 
    finally 
    DispatchTable.Free; 
    end; 
end. 

मैंने जो कार्यान्वयन लिखा वह जेनरिक का उपयोग करता है, इसलिए यह केवल डेल्फी 200+ के साथ काम करेगा। पुराने संस्करणों के लिए यह शायद TStringList और command pattern

+0

+1, खासकर डेल्फी 200 9 और इससे पहले के लिए। डेल्फी 2010+ के साथ, आरटीटीआई में पहले से ही सभी अंतर्निहित जानकारी है, इसलिए मोहम्मद और हेनरी का जवाब आसान है। –

+0

पेज नहीं मिला। – ZzZombo

+0

गंभीरता से? इसलिए अपनी वेबसाइट से लिंक अपडेट किए बिना एक प्रश्न को हटा दिया/हटा दिया? –

11

आपने अपना डेल्फी संस्करण निर्दिष्ट नहीं किया है, हालांकि यदि आपके पास डेल्फी 2010 (+) है तो आप इसे बढ़ाए गए आरटीटीआई का उपयोग करके कर सकते हैं, मैं नहीं हूं विशेषज्ञ उन पर है, लेकिन मैं आप के लिए इस नमूने की कोशिश की:

TProcClass = class 
    public 
     procedure SayHi; 
     function GetSum(X,Y:Integer): Integer; 
    end; 

uses 
    Rtti; 

{ TProcClass } 

procedure TProcClass.SayHi; 
begin 
    ShowMessage('Hi'); 
end; 

function TProcClass.GetSum(X, Y: Integer): Integer; 
begin 
    ShowMessage(IntToStr(X + Y)); 
end; 

procedure ExecMethod(MethodName:string; const Args: array of TValue); 
var 
R : TRttiContext; 
T : TRttiType; 
M : TRttiMethod; 
begin 
    T := R.GetType(TProcClass); 
    for M in t.GetMethods do 
    if (m.Parent = t) and (m.Name = MethodName)then 
     M.Invoke(TProcClass.Create,Args) 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    ExecMethod('SayHi',[]); 
    ExecMethod('GetSum',[10,20]); 
end; 

अच्छी बातें, यदि आप पैरामीटर के साथ प्रक्रिया या कार्य हो इसे और अधिक काम के बिना काम करेंगे।

+1

कृपया ध्यान दें कि यह कोड इस विधि से प्रत्येक विधि के लिए कम से कम एक 'TProcClass' उदाहरण को रिसाव करता है। –

8

डेल्फी 2010 के साथ आप पैरामीटर के साथ विधि का आह्वान करने के लिए JSON और SuperObject का उपयोग कर सकते हैं।

http://code.google.com/p/superobject/source/browse/#svn/trunk

आप की जरूरत है, वहाँ भी json के लिए एक्सएमएल को बदलने के लिए एक XML पार्सर है।

TForm1 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    procedure TestMethod(const value: string); 
    end; 

var 
    Form1: TForm1; 

implementation 
uses superobject; 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    SOInvoke(Self, 'TestMethod', SO('{value: "hello"}')); 
end; 

procedure TForm1.TestMethod(const value: string); 
begin 
    Caption := value; 
end; 
+0

यह बिंदु के बगल में है लेकिन अभी भी SuperObject के साथ करना है। मुझे पता है कि आप सही जगह पर सही आदमी हैं :-)। क्या आप [इस सवाल] पर थोड़ा ध्यान दे सकते हैं (http://stackoverflow.com/q/7841617/744588) कहीं SO पर? – menjaraz

5

प्रत्येक कार्य को एक क्रिया में रखें। तो फिर तुम नाम से कार्रवाई पा सकते हैं और निष्पादित यह

function ExecuteActionByName(const S: String); 
var 
    I: Integer; 
begin 
    for I := 0 to MainForm.ComponentCount-1 do 
    if (MainForm.Components[I] is TAction) 
    and SameText(TAction(MainForm.Components[I]).Name,S) then 
    begin 
     TAction(MainForm.Components[I]).Execute; 
     Break; 
    end; 
end; 
+0

+1; इस विचार के लिए दिलचस्प अवधारणा –

+0

@RobMcDonell +1। मैंने पुराने वीबी 6 में भी इसी तरह की चीज की है और मैं इसे लाजर को बंद करने की कोशिश कर रहा हूं (जिसे मैं बहुत नया हूं)। मुझे लगता है कि आपकी लाइन 'टीएक्शन (मेनफॉर्म.कंपोनेंट्स [आई])। निष्पादित करें;' पूरी चीज का केंद्र है। क्या आप कृपया आदेश पर उपयुक्त डॉक्टर को निर्देशित करेंगे? यहां तक ​​कि एक साधारण स्पष्टीकरण भी करेगा। धन्यवाद! – itsols

4

ठीक है, मैं बहुत देर पार्टी के लिए कर रहा हूँ, लेकिन आप निश्चित रूप से इस कोड के साथ नाम से दिनचर्या कॉल कर सकते हैं (कुछ सीमाएं सोचा हैं)

type 
    TExec = procedure of Object; 
    // rest of section... 

procedure TMainForm.ExecuteMethod(MethodName : String); 
var 
    Exec : TExec; 
    Routine : TMethod; 
begin 
    Routine.Data := Pointer(Form1); 
    Routine.Code := Form1.MethodAddress(MethodName); 
    if Not Assigned(Routine.Code) then 
     Exit; 

    Exec   := TExec(Routine); 
    Exec; 
end; 

शायद ज़रुरत पड़े कोई (बहुत दुर्लभ परिस्थितियों को छोड़कर) डेल्फी 7/2010

+0

क्षमा करें - मैं इस मंच के लिए काफी नया हूं। आप एफआईआर लाइन में किए गए मूल्य को कैसे असाइन कर सकते हैं?TExec क्या डेटा प्रकार है? – itsols

+1

@itsols: निश्चित रूप से मैंने अपना जवाब संपादित किया, मूल रूप से आप उस पंक्ति को डालते हैं जो 'TExec = ऑब्जेक्ट की प्रक्रिया;' * * टाइप * कीवर्ड के बाद * है और यह – TheDude

+0

+1 है ... यह अभी स्पष्ट है :) धन्यवाद! – itsols

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