سؤال

كتبت صفحات ASP.NET التي ستدير النماذج. إنهم يعتمدون على الفئة الأساسية التالية.

public abstract class FormPageBase<TInterface, TModel> : Page, IKeywordProvider 
        where TModel:ActiveRecordBase<MasterForm>, TInterface, new()
        where TInterface:IMasterForm
    {
        public TInterface FormData { get; set; }                   
     }

و Subclass عينة هنا:

public partial class PersonalDataFormPage : FormPageBase<IPersonalDataForm, PersonalDataForm>, IHasFormData<IPersonalDataForm>, IHasContact
    {
    }

أدناه لدي UserControl على الصفحة التي أريد "تستهلك" "FormData" من الصفحة حتى تتمكن من القراءة / الكتابة إليها.

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

ولكن عندما يحاول UserControl page page.formdata (بعد أن حاول أن يلقي الصفحة IHasFormData<IMasterForm> يخبرني أن الصفحة هي IHasFormData<IFormSubclass> على الرغم من أن لدي قيود على iformsubclass التي تقول إنها أيضا imasterform

هل هناك على أي حال يمكنني تناوله من الفئة الفرعية العامة إلى Superclass العامة أو هو هذا "التباين" وشيء C # 4.0؟

public abstract class FormControlBase<T> : UserControl, IKeywordProvider
    where T:IMasterForm 
{

    protected T FormData { get; set; }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

//This cast is failing when my common control's T does not exactly match
// the T of the Page.. even though the common controls TInterface is a base interface to the
//pages TInterface

        FormData = ((IHasFormData<T>) Page).FormData;

        if (!IsPostBack)
        {
            PopulateBaseListData();
            BindDataToControls();
        }
    }

    protected abstract void PopulateBaseListData();
    protected abstract void BindDataToControls();


    public abstract void SaveControlsToData();


    #region IKeywordProvider
    public List<IKeyword> GetKeywords(string categoryName)
    {
        if(!(Page is IKeywordProvider ))
            throw new InvalidOperationException("Page is not  IKeywordProvider");

        return ((IKeywordProvider) Page).GetKeywords(categoryName);
    }

    #endregion

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

المحلول

اسمحوا لي أولا أن أرى ما إذا كان يمكنني إعادة هذه المشكلة المعقدة بشكل أكثر إجزيا. لديك واجهة عامة IHasFormData<T>. وبعد لديك كائن معروف بالتنفيذ IHasFormData<IFormSubclass>. وبعد كنت ترغب في تحويله إلى IHasFormData<IMasterForm>. وبعد أنت تعرف أن هناك تحويل مرجعي من IFORMSUSCCLASS إلى ImasterForm. هذا فشل.

نعم؟

إذا كان هذا هو عبارة صحيحة للمشكلة، فهذا نعم، فهذه مسألة التباين الواجهة. C # 3 لا يدعم واجهة التباين. C # 4 سوف، إذا كنت تستطيع إثبات التحويل البرمجي أن التباين الآمن.

اسمحوا لي أن أصف لك لفترة وجيزة لماذا قد لا يكون هذا آمنا. لنفترض أن لديك فصول أبل والبرتقال والفواكه مع العلاقات الفيزيائية الواضحة الواضحة. انت تملك IList<Apple> الذي ترغب في طرحه IList<Fruit>. وبعد هذا التحويل Covariant ليس قانونيا في C # 4 ولا يمكن أن يكون قانونيا لأنه غير آمن. لنفترض أننا سمحنا بذلك. يمكنك بعد ذلك القيام بذلك:

IList<Apple> apples = new List<Apple>();
IList<Fruit> fruits = apples;
fruits.Add(new Orange()); 
// We just put an orange into a list of apples!  
// And now the runtime crashes.

لاحظ أن المشكلة هي أن List<T> يكشف الطريقة التي تأخذها حجة. من أجل التحويل البرمجي للسماح بتحويلات Covariant على واجهتك IHasFormData<T>, ، يجب أن تثبت إلى المحول البرمجي ذلك IHasFormData<T> يعرض أي شيء يأخذ حجة. سوف تفعل ذلك بإعلان الواجهة IHasFormData<out T>, ، معنى الذاكرة الهرمية "يظهر فقط في مواقع الإخراج". بعد ذلك، سيحقق المحول البرمجي أن مطالبتك صحيحة، وابدأ في السماح بتحويلات Covariant.

لمزيد من المعلومات حول هذه الميزة في C # 4، راجع أرشيف ملاحظات على تصميم الميزة:

http://blogs.msdn.com/ericlippert/archive/tags/covariance+and+contravariace/default.aspx.

نصائح أخرى

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

لدي صفحة أساسية مشابهة للغاية لك هذا هو كيف أعرف الألغام.

public abstract class ViewBasePage<TPresenter, TView> : Page, IView
        where TPresenter : Presenter<TView>
        where TView : IView
{
    protected TPresenter _presenter;

    public TPresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = (TView) ((IView) this);
        }
}

أعتقد أنك بحاجة إلى أن تكون مثل FormData = ((IHasFormData<T>) (IMasterForm )Page)).FormData;

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