0

I have two interfaces,

public interface IDocument<SegType> where SegType : ISegment

and

public interface ISegment

Basically, I want to enforce that each class that implements IDocument is composed of one type of ISegment, and that people using these classes never need to know about which type of ISegment their class uses internally.

I then created a class that implements IDocument<SegType> where SegType : ISegment :

public class MyDocument : IDocument<MySegment>

and the corresponding MySegment :

public class FffSegment : ISegment

All of this compiles and works just as I expect it to when I specify MyDocument as the type. Why can I not implicitly cast an instance of MyDocument to be of type IDocument<Isegment>? When I try the line:

IDocument<ISegment> doc = new MyDocument();

I get the error

Cannot implicitly convert type 'MyDocument' to 'IDocument<ISegment>'. An explicit conversion exists (are you missing a cast?)

But when I cast it, it just comes back null. If I change it to:

IDocument<MySegment> doc = new MyDocument();

it works, as it does when I change the class definition to

public class MyDocument : IDocument<ISegment>

Why can I not force a specific type that implements ISegment for that implementation of IDocument? I want to re-use this code for different types of IDocument and ISegment and maybe some day some implementations of IDocument will allow for multiple types of ISegment but MyDocument should be restricted against this kind of behavior. How can I enforce these requirements but still write code that is generic enough to be re-used in the future?

p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
Drewmate
  • 2,059
  • 2
  • 18
  • 27

2 Answers2

3

You need to get into the nastiness of co-and-contra variance:

public interface IDocument<out SegType> where SegType : ISegment
{}

I think that should make your example compile now...

Here's some reading material:

JerKimball
  • 16,584
  • 3
  • 43
  • 55
  • Thank you. This is exactly what I needed. That first msdn blog post link is especially interesting, and I think I'll have to read up on the other two as well. I should note that I had to make another minor change. `IDocument` had a return value on a method of `IList but apparently `IList` is not covariant. `IEnumerable` is, so I changed it to that. Figured that out from this SO question: http://stackoverflow.com/a/7416775/761590 – Drewmate Mar 01 '13 at 22:10
0

Because IDocument<MySegment> cannot cast directly to an IDocument<ISegment>. If it could, you could do this:

IDocument<ISegment> doc1 = new IDocument<MySegment>;
doc1.Add(new MyOtherSegment());   // invalid

(Assuming IDocument<T> has an Add(T newSegment) method)

Take a long look at your design and decide if generics are really necessary or if just using ISegment within IDocument is sufficient.

D Stanley
  • 149,601
  • 11
  • 178
  • 240