5

I have this desired class hierarchy:

interface IClass
{
    string print(IClass item);
}

class MyClass : IClass
{
    // invalid interface implementation
    // parameter type should be IClass not MyClass
    string print(MyClass item)
    { return item.ToString(); }
}

I tried to solve interface implementation problem by using generic types as next with no success:

interface IClass
{
    string print<T>(T item) where T : IClass;
}

class MyClass : IClass
{
    string print<T>(T item) where T : MyClass
    { return item.ToString(); }
}

What should I do?

4
  • You should make the interface itself generic and give the implementing class the desired type. Commented Apr 11, 2013 at 13:19
  • 1
    How about not having the parameter in the print method and make each subclass inject the IClass implementation into the contructor or a sertter. Commented Apr 11, 2013 at 13:19
  • 1
    The toString Method is inherited from Object, so why do you really need to have print(MyClass item) and not just print(Object item)? Do you hide this method? Commented Apr 11, 2013 at 13:19
  • It's just a simplified example of my real class hierarchy. Commented Apr 11, 2013 at 13:26

4 Answers 4

14

Make your interface generic

interface IClass<T>  where T : IClass<T>
{
     string print(T item);
}

class MyClass : IClass<MyClass>
{
    public string print(MyClass item)
    { 
       return item.ToString(); 
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Note that though this does work, (1) it is confusing, and (2) it does not necessarily enforce the restriction you wish to enforce. See blogs.msdn.com/b/ericlippert/archive/2011/02/03/… for some thoughts on this pattern.
@Eric, What do you suggest to solve the problem in a more clear manner?
can we use polymorphism with this solution?
11

It's helpful to understand why this is illegal. The feature you want is formal parameter type covariance, and very few languages offer it. (Eiffel, I think has this as a feature.) It is not often found in languages because it is not safe! Let me illustrate with an example:

class Animal {}
class Lion : Animal { public void Roar() { } }
class Giraffe : Animal { }
interface IFoo { void M(Animal a); }
class C : IFoo
{
    public void M(Lion lion) { lion.Roar(); }
}
class P
{
    public static void Main()
    {
        IFoo foo = new C();
        foo.M(new Giraffe()); 
    }
}

And we just made a giraffe roar.

If you look at all those type conversions, the only one that can sensibly be made illegal is matching C.M(Giraffe) to IFoo.M(Animal).

Now, formal parameter type contravariance is typesafe but it is not legal in C# except in some very limited circumstances. If C# supported it, which it does not, then you could safely do something like this:

interface IBar { void M(Giraffe g); }
class D : IBar
{
    public void M(Animal animal) { ... }
}
class P
{
    public static void Main()
    {
        IBar bar = new D();
        bar.M(new Giraffe()); 
    }
}

See what happened there? IFoo.M says "I can take a giraffe", and C.M says "I can accept any giraffe because in fact I can accept any animal". That would be typesafe if C# supported it, but it only supports it in two ways:

  • Contravariant generic delegate and interface conversions.
  • Contravariant method group conversions to delegate types.

An example of the first is that an expression of type IComparable<Animal> may be assigned to a variable of type IComparable<Giraffe> by the same logic: a method that compares two animals can be used where a method that compares two giraffes is needed. This was added in C# 4.

An example of the second is:

delegate void MyFunction(Giraffe g);
...
D d = new D();
MyFunction myfunc = d.M;

Again, we need a function that takes a Giraffe, and we supply one that takes any Animal. This feature was added in C# 2.

Comments

0

You just need to pass IClass as parameter to your method.

interface IClass
{
  string print(IClass item);
}

class MyClass : IClass
{
  public string print(IClass item)
  { return item.ToString(); }
}

3 Comments

My requirement is that the print method of MyClass should receive parameter of exactly MyClass and not of another IClass subclasses.
For now if we just ignore that one should program to interfaces - not implementation. whats wrong with the following interface? interface IClass { string print(MyClass item); }
Nothing. That's fine. But like said below @Eric Lippert it's confusing
0

Here's A solution that will get you compiling at least:

interface IClass
{
    string print<T>(T item) where T : IClass;
}

class MyClass : IClass
{   
    string print(IClass item) => item is MyClass i ? i.ToString() : string.Empty;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.