سؤال

مشكلتي هنا هي أنني أود اجتياز كائن إلى فئة مشتقة، ولكن يجب القيام به قبل منشئ الطبقة الأساسية، لأن الفئة الأساسية ستدعو الفئة المشتقة على الفور Start() الطريقة التي تستخدم الكائن.

إليك مقتطف من الفئة الأساسية، (تمت إعادة تسميته من ماسح الباركود للراحة).

public abstract class MyBase
{    
    public MyBase()
    {
        if (Initialize())
            this.Start();
    }

    public abstract bool Initialize();
    public abstract void Start();
}

إليك الطبقة المشتقة التي أخلقها.

class MyDerived : MyBase
{
    private string sampleObject;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
    }

    public override bool Initialize() 
    { 
        return GetDevice();
    }
    public override void Start() 
    { 
        Console.WriteLine("Processing " + sampleObject.ToString()); 
    }
}

أشك في أنه يمكنك جعل C # تنفيذ منشئ مشتق قبل منشئ الأساس؛ لذلك أنا حقا أبحث عن حلا لتمرير كائن إلى الفئة المشتقة قبل استخدام الكائن.

لقد حصلت حول هذا عن طريق وضع التهيئة / البدء إذا كتلة داخل MyDerived البناء. ومع ذلك، هناك فصول أخرى مستمدة من الفئة الأساسية؛ لذلك انتهى بي الأمر إلى تكرار هذه الكتلة من رمز التهيئة / البداية في كل فئة مشتقة. أود أن أرى بديلا لتعديل الفئة الأساسية.

هل كانت مفيدة؟

المحلول

ما تحاول القيام به هو مستحيل في C #. يجب تشغيل المنشئ في فئة أساسية قبل منشئ أي فئة مشتقة وإلا سيكون هناك محتمل لحالة الكائن الفاسد. يجب أن يكون كائن طفل قادر على افتراض أن قاعدتها مصنوعة بالكامل ومتاحة.

نصائح أخرى

IMHO التصميم الخاص بك خطأ. يجب أن لا تبدأ العملية من داخل المنشئ. يجب أن يستدعي رمز الاستهلاك الخاص بك بطريقة البداية () بشكل صريح عند الاقتضاء.

وأود أن إعادة صياغة التصميم الخاص بك بحيث تهيئة (وربما تبدأ () - على الرغم من أنني عادة ما تكون هذه طريقة عامة مدعومة من قبل المستخدم) تسمى بعد البناء.

إذا كنت تقوم بعمل Barcodescanner، فيمكنك القيام بذلك في المرة الأولى التي تذهب فيها إلى المسح الضوئي. مجرد تهيئة أعضائك فقط باستخدام البيانات من الفئة المشتقة.

سيعمل هذا حول مشكلتك، دون تغيير حقيقي في الاستخدام من المستخدم.

آسف للإضافة إلى مؤشر ترابط قديم، ولكن ربما شخص ما مهتما بإجابة أخرى. لقد وجدت طريقة أنيقة (IMO) للتعامل مع المنطق القيام بشيء أكثر من (وبعد) مجرد تعيين الحقول في منشئ الطبقة حيث يتورط الميراث هناوبعد إذا كنت ترغب فقط في الحصول على هذا التسلسل الهرمي المحدد وليس استخدام الحل العام مع واجهة وطريقة تمديد، فيمكنك استخدام نفس المفهوم في شجرة فئة واحدة مثل هذا:

public abstract class MyBase
{    
    protected MyBase()
    {
        if (Initialize(this)) // just to illustrate; this will never pass here as this class is abstract
            this.Start();
    }

    protected bool IsInitialized { get; private set; } = false;

    protected static bool Initialize<T>(T instance) where T: MyBase
    {
        if (instance?.GetType() == typeof(T)) // check if this is called from the constructor of instance run time type
            return instance.IsInitialized || ( instance.IsInitialized = instance.Initialize() );
        return false;
    }

    protected abstract bool Initialize();
    public abstract void Start();
}

ومشتق:

class MyDerived : MyBase
{
    private string sampleObject;
    protected bool started = false;

    public MyDerived (string initObject)
    {
        sampleObject = initObject;
        if (Initialize(this)) // if this is the most derived constructor, this will run Initialize() and return whether it was successful
            this.Start();
    }

    protected override bool Initialize() 
    { 
       return GetDevice();
    }

    public override void Start() 
    { 
        // if Start() would be protected, we don't need the IsInitialized property and we can move this check to the constructor on the returned value of the Initialize<T>() call.
        if (!IsInitialized) throw new InvalidOperationException("Initialization failed.");
        // if you want to have this method exposed public, we need to check if this instance is successfully initialized from the constructor and not in started state already.
        if (started) return;

        Console.WriteLine("Processing " + sampleObject.ToString()); 
        started = true;
        if (!Run(sampleObject)) started = false;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top