简体   繁体   中英

Returning a class that implements a variant interface

Background:

I have three Silverlight Pages, that implement my interface:

interface IPageWithData<in T> where T : Entity
{
    void SetData(T obj);
}

public class APage : Page, IPageWithData<AItem> { /* Implementation */ }
public class BPage : Page, IPageWithData<BItem> { /* Implementation */ }
public class CPage : Page, IPageWithData<CItem> { /* Implementation */ }

// AItem, BItem and CItem are (EF) Entities (they are derived from Entity class).

Then I use a custom manager that returns a page that relates to the treeview node given as a parameter:

private static class PageContainerHelper
{
    public static IPageWithData<Entity> SetPage(RadTreeViewItem selectedNode)
    {
        APageRTVI aNode = selectedNode as APageRTVI;
        BPageRTVI bNode = selectedNode as BPageRTVI;
        CPageRTVI cNode = selectedNode as CPageRTVI;

        if (aNode != null)
        {
            if (APage == null)
                APage = new APage();

            APage.SetData(aNode.aItem);
            return APage; // ERROR HERE
        }

        /*
            ... the same for BPageRTVI and CPageRTVI
        */
    }

    public static APage APage { get; set; }
    public static BPage BPage { get; set; }
    public static CPage CPage { get; set; }
}

Problem:

I seem to be understanding co/contravariance the wrong way. The SetPage() method doesn't allow me to return APage :

Cannot implicitly convert type 'MyProject.Views.Pages.APage' to 'MyProject.Views.Pages.IPageWithData' . An explicit conversion exists (are you missing a cast?)

APage implements IPageWithData<T> (albeit T is of a more derived type). Why does this require a explicit conversion? And would an explicit conversion even work here?

So basically, there are two things I need. One is that when SetPage is returning a page, it can use a page that implements IPageWithData of a type that is more derived than Entity . And the other thing I need is for the IPageWithData<T>.SetData method to be able to receive arguments that are of a type more derived than a T , that is Entity .

Is this possible?

Consider what you can do with IPageWithData<Entity> . You can do:

IPageWithData<Entity> pageWithData = PageContainerHelper.SetPage(...);
BItem item = new BItem();
pageWithData.SetData(item);

Now the implementation is an APage - what would you want it to be able to do with a BItem ? I suspect you don't want that.

In other words, the compiler is doing exactly what it should - it's protecting you from sending the wrong kind of data to a page which can't handle it. Quite how you want to fix this, I don't really know - I suspect you want SetPage to be generic too:

public static IPageWithData<T> SetPage<T>(RadTreeViewItem selectedNode)
    where T : Entity

but it's not clear to me what that does to your implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM