2010-10-28 5 views
10

मुझे किसी तृतीय-पक्ष घटक को ठीक करने की आवश्यकता है।डेल्फी: वंश के वर्ग में निजी पूर्वजों के क्षेत्र को लिखना

TThirdPartyComponentBase = class 
private 
    FSomeVar: Integer; 
public 
    ... 
end; 

TThirdPartyComponent = class (TThirdPartyComponentBase) 
protected 
    procedure Foo; virtual; 
end; 

procedure TThirdPartyComponent.Foo; 
begin 
    FSomeVar := 1; // ACCESSING PRIVATE FIELD! 
end; 

यह काम करता है क्योंकि दोनों वर्गों एक ही इकाई में हैं, इसलिए वे इस किस्म की "मित्र" कर रहे हैं: इस घटक की क्लास निजी चर जो सक्रिय रूप से अपने वंश द्वारा प्रयोग किया जाता है।

लेकिन अगर मैं एक नई इकाई

TMyFixedComponent = class (TThirdPartyComponent) 
    procedure Foo; override; 
end; 

मैं FSomeVar अब और उपयोग नहीं कर सकते में एक नया वर्ग बनाने की कोशिश करता हूँ, लेकिन मैं अपने को ठीक करने के लिए इसका इस्तेमाल करने की जरूरत है। और मैं वास्तव में बेस क्लास के उस पेड़ के अपने कोड में पुन: पेश नहीं करना चाहता हूं।

क्या आप उस मूल क्षेत्र तक पहुंचने के लिए कुछ त्वरित हैक की सलाह दे सकते हैं, मूल घटक की इकाई को बदले बिना यह संभव है?

उत्तर

5

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

__TThirdPartyComponentBase(Self).FSomeVar := 123; 
बेशक

, कि खतरनाक है:

type 
    __TThirdPartyComponentBase = class 
    private 
    FSomeVar: Integer; 
    end; 

तो पहुँच जाते हैं। क्योंकि यदि फ़ील्ड लेआउट बदल दिया जाएगा और आप इस तथ्य को याद करेंगे, तो उपर्युक्त दृष्टिकोण असफलताओं, एवी, इत्यादि का कारण बन जाएगा

+2

@ एंड्रयू: ध्यान दें कि जैसे ही पूर्वजों (तृतीय पक्ष) घटक परिवर्तन के मेमोरी लेआउट के रूप में यह समाधान टूट जाएगा। हो सकता है कि आप इसे ब्रेक न करें, क्योंकि कुछ भी आपको इसके बारे में चेतावनी नहीं देगा। या आप नकली गलत व्यवहार देख सकते हैं (यदि आप भाग्यशाली हैं: अभिगम उल्लंघन) क्योंकि आप उस डेटा को ओवरराइट करना शुरू करते हैं जो आपका नहीं है। –

+0

@ जेरोइन प्लूइमर मैंने एंड्रयू को उस तथ्य के बारे में नोटिस किया है। लेकिन इस मुद्दे के लिए कोई अन्य समाधान नहीं है। – oodesigner

+0

क्लास हेल्पर्स हैकिंग के बिना ऐसा कर सकते हैं, मेरा जवाब देखें :) –

-1

TThirdPartyComponent में एक सुरक्षित संपत्ति द्वारा निजी चर के मूल्य का पर्दाफाश करें।

TThirdPartyComponent = class (TThirdPartyComponentBase) 
private 
    Procedure SetValue(Value: Integer); 
    Function GetValue: Integer; 
protected 
    Property MyVar: Integer read GetValue write Setvalue; 
    procedure Foo; virtual; 
end; 

Procedure TThirdPartyComponent.SetValue(Value: Integer); 
begin 
    FSomeVar := Value ; 
end; 

Function GetValue: Integer; 
begin 
    result := FSomeVar; 
end; 

TMyFixedComponent कक्षा में प्रक्रिया है जिससे आप ओवरराइड करना चाहेंगे में MyVar संपत्ति का उपयोग करें।

+5

लेकिन यह TThirdPartyComponent का मूल कोड बदल देगा। मैं TThirdPartyComponent के कोड को फिर से लिखने या मूल घटक की इकाई को बदलने के बिना कुछ समाधान चाहता था। – Andrew

0

यह नहीं पता कि इससे मदद मिलेगी, लेकिन मुझे याद है कि एक तरीका है दृश्यता में एक निजी चर "क्रैक" करने के लिए।

मुझे पता है, उदाहरण के लिए, मुझे संकलक से चेतावनियों का सामना करना पड़ा है जब मैंने कम दृश्यता (बेस क्लास में) से अधिक दृश्यमान स्तर (मेरे वंशज में) में एक संपत्ति स्थानांतरित की है। चेतावनी में कहा गया है कि इसे दृश्यता के एक अलग स्तर पर घोषित किया जा रहा है ...

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

क्षमा करें मेरे पास ऐसा करने के तरीके के बारे में अधिक विशिष्ट जानकारी नहीं है (यदि यह वास्तव में संभव है।) शायद यह पोस्टिंग यहां विज़ार्डों में से एक को संकेत देगी मुझे सुधारने में! :-)

18

class helpers के उपयोग से व्युत्पन्न वर्ग से बेस क्लास के निजी हिस्सों तक पहुंच को सुरक्षित रखने के बिना संभव है।

बस एक और इकाई में इन घोषणाओं जोड़ें:

Uses YourThirdPartyComponent; 

type 
    // A helper to the base class to expose FSomeVar 
    TMyBaseHelper = class helper for TThirdPartyComponentBase 
    private 
    procedure SetSomeVar(value : integer); 
    function GetSomeVar: integer; 
    public 
    property SomeVar:integer read GetSomeVar write SetSomeVar; 
    end; 

    TMyFixedComponent = class helper for TThirdPartyComponent 
    protected 
    procedure Foo; 
    end; 

procedure TMyFixedComponent.Foo; 
begin 
    // Cast to base class and by the class helper TMyBaseHelper the access is resolved 
    TThirdPartyComponentBase(Self).SomeVar := 1; 
end; 

function TMyBaseHelper.GetSomeVar: integer; 
begin 
    Result := Self.FSomeVar; // ACCESSING PRIVATE FIELD! 
end; 

procedure TMyBaseHelper.SetSomeVar(value: integer); 
begin 
    Self.FSomeVar := value; // ACCESSING PRIVATE FIELD! 
end; 

// Testing 
var 
    TSV: TThirdPartyComponent; 
begin 
    TSV := TThirdPartyComponent.Create; 
    try 
    TSV.Foo;  
    WriteLn(IntToStr(TSV.SomeVar)); // Writes 1 
    finally 
    TSV.Free; 
    end; 
end. 

के रूप में कोड में टिप्पणियां से देखा जा सकता, FSomeVarTThirdPartyComponentBase वर्ग से एक वर्ग के सहायक द्वारा सामने आ रहा है। TThirdPartyComponent के लिए एक और कक्षा सहायक फू प्रक्रिया लागू करता है। वहां, बेस क्लास हेल्पर की SomeVar संपत्ति तक पहुंच बेस क्लास में एक प्रकार के कलाकार के माध्यम से बनाई जाती है।

+1

बहुत अच्छा! मुझें यह पसंद है। –

+3

ध्यान दें कि किसी अन्य इकाई में कक्षा सहायक अब डेल्फी 10.1 बर्लिन के रूप में निजी सदस्यों तक नहीं पहुंच सकते हैं, क्योंकि इसे एम्बरकेडेरो द्वारा एक बग के रूप में माना जाता था। अधिक जानकारी के लिए http://stackoverflow.com/questions/9410485/how-do-i-use-class-helpers-to-access-strict-private-members-of-a-class#comment61026976_9410717 देखें –

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