Pregunta

he escrito las páginas ASP.NET que se encargará de formas. Se basan en la siguiente clase base.

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

Y es una subclase de muestra aquí:

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

A continuación tengo un control de usuario en la página de la que quiero "consumir" el "FormData" de la página para que se pueda leer / escribir en él.

Entonces, tener un mayor control de usuario "común" que yo quiero tener operar en la interfaz de base de todas mis forman subclases ... IMasterForm

Sin embargo, cuando el control de usuario intenta fundición Page.FormData (después de haber probado a la página fundido a IHasFormData<IMasterForm> me dice que la página se IHasFormData<IFormSubclass> pesar de que tienen una restricción en la IFormSubclass que dice que también es IMasterForm

¿Hay alguna forma que yo pueda entregado desde la subclase genérica a la superclase genérica o se trata de "covarianza" y 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

}
¿Fue útil?

Solución

Permítanme en primer lugar a ver si puedo reiterar este complicado problema de forma más sucinta. Tiene una interfaz genérica IHasFormData<T>. Se tiene un objeto que es conocido por aplicar IHasFormData<IFormSubclass>. Si desea cambiar a IHasFormData<IMasterForm>. Usted sabe que hay una conversión de referencia desde IFormSubclass a IMasterForm. Esta falla.

Sí?

Si esto es una declaración correcta del problema, entonces sí, se trata de una cuestión de covarianza interfaz. C # 3 no es compatible con la interfaz de covarianza. C # 4, si se puede demostrar al compilador que la covarianza es seguro.

Permítaseme describir brevemente por qué esto podría no ser seguro. Suponga que tiene clases de manzana, naranja y fruta con las relaciones de subclases obvias. Tiene una IList<Apple> que le gustaría echar a IList<Fruit>. Covariante que la conversión no es legal en C # 4 y no puede ser legal, ya que no es seguro. Supongamos que lo permitiera. A continuación, podría hacer esto:

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.

Tenga en cuenta que el problema es que List<T> expone un método que toma una camiseta como un argumento. Para que el compilador para permitir conversiones covariantes en su IHasFormData<T> interfaz, debe demostrar al compilador que IHasFormData<T> expone nada que tenga una T como un argumento. Que va a hacer que al declarar la IHasFormData<out T> interfaz, un significado mnemotécnico "T sólo aparece en los puestos de salida". El compilador continuación, compruebe que su reclamación es correcta, y empezar a permitir que las conversiones covariantes.

Para obtener más información sobre esta función en C # 4, ver mi archivo de notas sobre el diseño de la función:

http://blogs.msdn.com/ ericlippert / archivo / etiquetas / covarianza + y + contravarianza / default.aspx

Otros consejos

C # antes de 4.0 exige que todos los arroja a los tipos genéricos para que coincida con el parámetro de tipo exactamente. 4.0 presenta co- y contra-varianza, pero el reparto que está intentando realizar es imposible en las versiones anteriores.

Tengo una página base muy similar a la suya así es como defino la mía.

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

Creo que tiene que ser algo así como FormData = ((IHasFormData<T>) (IMasterForm )Page)).FormData;

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top