Domanda

ho scritto le pagine ASP.NET che gestirà le forme. Stanno sulla base della seguente classe di base.

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

E una sottoclasse campione è qui:

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

Qui di seguito ho un UserControl sulla pagina di cui voglio "consumare" il "formdata" dalla pagina in modo che possa leggere / scrivere ad esso.

Ho poi, avere un maggiore controllo utente "comune" che voglio avere operare sul interfaccia di base di tutti i miei sottoclassi di forma ... IMasterForm

Ma quando l'UserControl cerca colata Page.FormData (aver tentato di gettare pagina ad IHasFormData<IMasterForm> mi dice che la pagina è IHasFormData<IFormSubclass> anche se ho un vincolo sulla IFormSubclass che dice che è anche IMasterForm

È comunque ci che posso caccio dalla sottoclasse generica alla superclasse generici o è questo "covarianza" e una cosa 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

}
È stato utile?

Soluzione

Permettetemi innanzitutto di vedere se riesco a riformulare questo problema complicato più brevemente. Si dispone di un IHasFormData<T> interfaccia generica. Si dispone di un oggetto che è noto per implementare IHasFormData<IFormSubclass>. Si desidera convertire a IHasFormData<IMasterForm>. Voi sapete che c'è una conversione di riferimento da IFormSubclass a IMasterForm. Ciò non è riuscito.

Sì?

Se questo è una corretta dichiarazione del problema, allora sì, questa è una questione di interfaccia di covarianza. C # 3 non supporta l'interfaccia di covarianza. C # 4 sarà, se si può dimostrare al compilatore che covarianza è sicuro.

Vorrei descrivere per voi brevemente perché questo potrebbe non essere al sicuro. Supponiamo di avere classi di mela, arancia e frutta con le relazioni sottoclasse evidenti. Hai IList<Apple> che si desidera lanciare a IList<Fruit>. Che la conversione covariante non è legale in C # 4 e non può essere legale perché non è sicuro. Supponiamo di permesso. Si potrebbe quindi fare questo:

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.

Si noti che il problema è che List<T> espone un metodo che accetta un T come argomento. Affinché il compilatore per consentire conversioni covarianti sul IHasFormData<T> interfaccia, è necessario dimostrare al compilatore che IHasFormData<T> espone nulla che prende una T come argomento. Farete che dichiarando la IHasFormData<out T> di interfaccia, un significato mnemonico "T appare solo nelle posizioni di uscita". Il compilatore quindi verificare che il vostro reclamo è corretto, e iniziare permettendo alle conversioni covarianti.

Per ulteriori informazioni su questa funzione in C # 4, vedere il mio archivio di note sulla progettazione della funzione:

http://blogs.msdn.com/ ericlippert / archivio / tag / covarianza + e + controvarianza / default.aspx

Altri suggerimenti

C # prima del 4.0 richiede tutti i calchi di tipi generici in base al parametro di tipo esattamente. 4.0 introduce co- e contro-varianza, ma il cast si sta tentando di eseguire è impossibile nelle versioni precedenti.

Ho una pagina di base molto simili ai tuoi questo è come mi definisco il mio.

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);
        }
}

Credo che tu debba essere qualcosa di simile FormData = ((IHasFormData<T>) (IMasterForm )Page)).FormData;

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top