Frage

Ich schrieb ASP.NET-Seiten, die Formulare verwalten. Sie sind auf der folgenden Basisklasse basiert.

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

Und eine Probe SubClass ist hier:

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

Im Folgenden Ich habe eine Usercontrol auf der Seite, die ich will „verbrauchen“ die „Formdata“ von der Seite, so dass er / schreiben, um es lesen kann.

ich dann, haben eine „gemeinsame“ Benutzersteuerung, die ich auf der Basis Schnittstelle arbeiten zu wollen alle meine Form Subklassen ... IMasterForm

Aber wenn das Usercontrol Page.FormData versucht Gießen (versucht zu haben Seite zu gieße IHasFormData<IMasterForm> es mir sagt, dass die Seite IHasFormData<IFormSubclass> wird, obwohl ich eine Einschränkung für die IFormSubclass haben, der sagt, es ist auch IMasterForm

Gibt es trotzdem, dass ich von der generischen Unterklasse auf die generische Super werfen kann oder diese „Kovarianz“ und ein C # 4.0, was?

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

}
War es hilfreich?

Lösung

Lassen Sie mich zuerst sehen, ob ich dieses komplizierte Problem kurz und bündig mehr neu formulieren kann. Sie haben eine generische Schnittstelle IHasFormData<T>. Sie haben ein Objekt, das IHasFormData<IFormSubclass> zu implementieren, ist bekannt. Sie möchten es konvertieren IHasFormData<IMasterForm>. Sie wissen, dass es eine Referenzkonvertierung von IFormSubclass zu IMasterForm ist. Dies schlägt fehl.

Ja?

Wenn das eine korrekte Aussage des Problems ist, dann ja, das ist eine Frage der Schnittstelle Kovarianz. C # 3 unterstützt keine Schnittstelle Kovarianz. C # 4 wird, , wenn Sie die Compiler unter Beweis stellen können, die Kovarianz sicher ist.

Lassen Sie mich Ihnen kurz beschreiben, warum dies nicht sicher sein könnte. Angenommen, Sie haben Klassen Apfel, Orange und Frucht mit den offensichtlichen Subklassifizieren Beziehungen. Sie haben eine IList<Apple>, die Sie IList<Fruit> werfen möchten. Die covariant Umwandlung ist in C # 4 nicht legal und kann nicht legal sein, weil es nicht sicher ist. Angenommen, wir es erlaubt. Man könnte dies dann tun:

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.

Beachten Sie, dass das Problem, dass List<T> ist aussetzt, ein Verfahren, das eine T als Argument. Damit die Compiler covariant Conversions auf Ihrer Schnittstelle IHasFormData<T> zu ermöglichen, müssen Sie den Compiler beweisen, dass nichts IHasFormData<T> aussetzt, die ein T als Argument. Sie werden das tun, indem Sie die Schnittstelle IHasFormData<out T> erklärt, eine mnemonische Bedeutung „T erscheint nur in Ausgangspositionen“. Der Compiler wird dann überprüfen, ob Ihr Anspruch korrekt ist, und starten Sie die kovariante Konvertierungen ermöglichen.

Für weitere Informationen über diese Funktion in C # 4, mein Archiv von Notizen auf dem Design der Funktion finden Sie unter:

http://blogs.msdn.com/ ericlippert / Archiv / tags / Kovarianz + und + Kontra / default.aspx

Andere Tipps

C # vor 4.0 erfordert alle generischen Typen wirft genau die Parameter übereinstimmen. 4.0 führt Ko- und Kontravarianz, aber die Besetzung Sie ausführen möchten, ist in früheren Versionen nicht möglich.

Ich habe eine sehr ähnliche Basisseite zu Ihnen dieser ist, wie ich meine zu definieren.

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

Ich glaube, Sie so etwas wie FormData = ((IHasFormData<T>) (IMasterForm )Page)).FormData; sein müssen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top