views:

198

answers:

3

Maybe I'm dumb but ...

I have:

public interface IRequest
{
    IList<IRequestDetail> Details { get; set; }

    // stuff
}

public interface IRequestDetail
{
    // stuff
}

I then have:

public class MyRequest : IRequest
{
    IList<MyRequestDetail> Details {get; set; }

    // stuff
}

public class MyRequestDetail : IRequestDetail
{
    // stuff
}

It doesn't work.

C# gets pissed at me because MyRequest does not implement the interface due to not having an IList of IRequestDetail.

Now if I change it so the Details is IList of IRequestDetail I then have to cast it to MyRequestDetail everywhere in the code I use a non-interface member (I have several requests that share common stuff, but then specialize).

I kind of understand why its wrong, but not fully!

+5  A: 

I think, based on the question that the problem is that you want to treat Details as a generic list and enforce that it implements IRequestDetail. You also want it to be more specifically typed for the implementing classes. In this case, you need to make IRequest generic.

Try this:

public interface IRequest<T> where T : IRequestDetail
{
    IList<T> Details { get; set; }

    // stuff
}

public class MyRequest : IRequest<MyRequestDetail>
{
    public IList<MyRequestDetail> Details {get; set; }

    // stuff
}

This should work for you.

Michael Meadows
+1  A: 

Exact. Michael has the solution. the problem is a little trickier.

its that there is no explicit conversion from

IList<MyRequestDetail>

to

IList<IRequestDetail>

because that would imply that you can add other objects, that are based on different classes (e.g. MyRequestDetail2), that are not "MyRequestDetail" to the second object. and that would be illegal for the first.

cRichter
Okay, I felt like it made sense why it didn't work... but couldn't explain exactly why. That explains exactly why it shouldn't work.
eyston
You do lose the ability to cast the list due to lack of covariance (pre-4.0, see @Reed Copsey's answer: (http://stackoverflow.com/questions/807720/interface-with-a-list-of-interfaces/807791#807791). It's also true that in my answer, MyRequest can't be cast to IRequest<IRequestDetail> while it can be cast to IRequest<MyRequestDetail>. It becomes a problem when the generic type is not available to referencing libraries/executables.
Michael Meadows
+1  A: 

This is due to covariance and contravariance in C#. There is a very detailed, very clear explaination of the issues (split into many parts) on Eric Lippert's Blog.

Reed Copsey