سؤال

لست متأكدًا مما إذا كان هذا أمرًا غريبًا أم لا، أو إذا كان الأمر يتعلق بطريقة ما برائحة الكود ... لكنني كنت أتساءل عما إذا كانت هناك طريقة (سيكون نوع ما من أنماط oop لطيفًا) "للإرسال" نوع أساسي إلى نموذج من نوعه المشتق.أعلم أن هذا غير منطقي لأن النوع المشتق سيكون له وظائف إضافية لا يقدمها الوالد وهي في حد ذاتها ليست سليمة بشكل أساسي.ولكن هل هناك طريقة ما للقيام بذلك؟فيما يلي مثال للتعليمات البرمجية حتى أتمكن من شرح ما أطلبه بشكل أفضل.

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}

أعلم أن هذا يبدو أبلهًا ولكن هل هناك أي طريقة لإنجاز شيء من هذا النوع؟

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

المحلول

ليس بشكل سليم، في اللغات "المدارة".هذا هو إسقاط, ، ولا توجد طريقة عقلانية للتعامل معها، للسبب الذي وصفته بالضبط (توفر الفئات الفرعية أكثر من الفئات الأساسية - من أين يأتي هذا "المزيد"؟).إذا كنت تريد حقًا سلوكًا مشابهًا لتسلسل هرمي معين، فيمكنك استخدام المُنشئات للأنواع المشتقة التي ستأخذ النوع الأساسي كنموذج أولي.

يمكن للمرء أن يبني شيئًا ما مع التأمل الذي يتعامل مع الحالات البسيطة (أنواع أكثر تحديدًا ليس لها حالة إضافة).بشكل عام، مجرد إعادة تصميم لتجنب المشكلة.

يحرر:عفوًا، لا يمكن كتابة عوامل التحويل بين الأنواع الأساسية/المشتقة.من الغريب أن تحاول Microsoft "حمايتك" من نفسك.حسنًا، على الأقل ليسوا سيئين مثل صن.

نصائح أخرى

حاول التكوين بدلا من الميراث!

يبدو لي أنه من الأفضل لك تمرير مثيل SomeBaseClass إلى SomeDerivedClass (والذي لن يستمد الفئة الأساسية بعد الآن، ويجب إعادة تسميته على هذا النحو)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}

الدفع http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html (الصفحة 3):

يوفر إعادة استخدام الكود عبر تكوين التكوين طريقة بديلة لـ Apple لإعادة استخدام تطبيق Fruit of Peel ().بدلاً من تمديد الفاكهة ، يمكن لـ Apple الاحتفاظ بمثيل الفاكهة وتحديد طريقة Peel () الخاصة التي تستدعي ببساطة Peel () على الفاكهة.

أنا شخصياً لا أعتقد أن الأمر يستحق عناء استخدام الميراث في هذه الحالة.بدلاً من ذلك، قم فقط بتمرير مثيل الفئة الأساسية في المُنشئ والوصول إليه من خلال متغير العضو.

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}

يعد Downcasting منطقيًا، إذا كان لديك كائن من فئة مشتقة ولكن تتم الإشارة إليه بواسطة مرجع من نوع الفئة الأساسية ولسبب ما تريد إعادته إلى مرجع من نوع فئة مشتقة.بمعنى آخر يمكنك البث الهابط لعكس تأثير البث التصاعدي السابق.ولكن لا يمكن أن يكون لديك كائن من الفئة الأساسية يتم الرجوع إليه بواسطة مرجع من نوع فئة مشتق.

أنا لا أقول أنني أوصي بهذا.ولكن يمكنك تحويل الفئة الأساسية إلى سلسلة JSON ثم تحويلها إلى الفئة المشتقة.

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));

لا، هذا غير ممكن.في لغة مُدارة مثل C#، لن ينجح الأمر.لن يسمح وقت التشغيل بذلك، حتى لو سمح المترجم بذلك.

لقد قلت بنفسك أن هذا يبدو أبلهًا:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

لذا اسأل نفسك، هل class في الواقع مثال على SomeDerivedClass؟لا، وبالتالي فإن التحويل لا معنى له.إذا كنت بحاجة إلى تحويل SomeBaseClass ل SomeDerivedClass, ، فيجب عليك توفير نوع من التحويل، إما مُنشئًا أو طريقة تحويل.

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

لا تسمح لغة C# بمثل هذه العوامل، ولكن لا يزال بإمكانك كتابتها وهي تعمل:

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }

نعم - هذه رائحة رمزية، وتؤكد إلى حد كبير حقيقة أن سلسلة ميراثك مكسورة.

لي يخمن (من العينة المحدودة) هو أنك تفضل أن تعمل DerivedClass على مثيل SomeBaseClass - بحيث يكون "DerivedClass لديه SomeBaseClass"، بدلاً من "DerivedClass هو SomeBaseClass".وهذا ما يُعرف بـ "تفضيل الصلح على الميراث".

كما لاحظ آخرون، فإن الاختيار الذي تقترحه ليس ممكنًا حقًا.هل ربما تكون هذه هي الحالة التي يكون فيها نمط الديكور(مستخلص الرأس الأول) هل يمكن إدخاله؟

هل فكرت في الواجهة التي سيتم تنفيذها حاليًا من خلال فئتك الأساسية وفئتك المشتقة؟لا أعرف تفاصيل سبب تنفيذك بهذه الطريقة ولكنها قد تنجح.

وهذا ما يسمى البث السلبي واقتراح Seldaek باستخدام الإصدار "الآمن" سليم.

وهنا لائق جدا الوصف مع عينات التعليمات البرمجية.

هذا غير ممكن لأنه كيف ستحصل على "الإضافي" الذي تمتلكه الفئة المشتقة.كيف يعرف المترجم أنك تعني مشتقة Class1 وليس مشتقة فئة 2 عند إنشاء مثيل لها؟

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

لا أعرف لماذا لم يقل أحد هذا وربما فاتني شيء ما ولكن يمكنك استخدام الكلمة الرئيسية كـ وإذا كنت بحاجة إلى استخدام عبارة if.

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-يحرر- لقد طرحت هذا السؤال منذ فترة طويلة

لقد كنت مؤخرًا في حاجة إلى توسيع DTO بسيط بنوع مشتق من أجل وضع المزيد من الخصائص عليه.ثم أردت إعادة استخدام بعض منطق التحويل الذي كان لدي، من أنواع قواعد البيانات الداخلية إلى DTOs.

الطريقة التي قمت بحلها كانت من خلال فرض مُنشئ فارغ على فئات DTO، باستخدامه على النحو التالي:

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

يمكنني بعد ذلك إعادة استخدام منطق التحويل من DTO البسيط عند التحويل إلى المنطق المعقد.بالطبع، سيتعين علي ملء خصائص النوع المعقد بطريقة أخرى، ولكن مع العديد والعديد من خصائص DTO البسيطة، فإن هذا يبسط الأمور حقًا في IMO.

هذا لا يمكن أن ينجح.انتقل إلى صفحة المساعدة المرتبطة بخطأ الترجمة.

الحل الأفضل هو استخدام أساليب المصنع هنا.

كما أشارت العديد من الإجابات، لا يمكنك الإحباط وهو أمر منطقي تمامًا.

ومع ذلك، في حالتك، SomeDerivedClass لا يحتوي على خصائص ستكون "مفقودة".لذلك يمكنك إنشاء طريقة تمديد مثل هذا:

public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}

إذن أنت لا تقوم بالإرسال، بل تقوم فقط بالتحويل:

SomeBaseClass b = new SomeBaseClass();
SomeDerivedClass c = b.ToDerived<SomeDerivedClass>();

يعمل هذا فقط إذا كانت جميع البيانات الموجودة في الفئة الأساسية في شكل خصائص قابلة للقراءة والكتابة.

يعالجها C++ باستخدام مُنشئ. الكتابة بلغة C++.يبدو وكأنه سهو بالنسبة لي.لقد طرح الكثير منكم مسألة ما ستفعله العملية بالخصائص الإضافية.أود أن أجيب، ماذا يفعل المترجم عندما يقوم بإنشاء فئة مشتقة عندما لا يقوم المبرمج بتعيين الخصائص؟لقد تعاملت مع هذا الموقف بشكل مشابه لـ C++.أقوم بإنشاء مُنشئ يأخذ الفئة الأساسية ثم قم بتعيين الخصائص يدويًا في المُنشئ.وهذا بالتأكيد أفضل من تعيين متغير في الفئة المشتقة وكسر الميراث.سأختاره أيضًا بدلاً من طريقة المصنع لأنني أعتقد أن الكود الناتج سيكون أكثر نظافة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top