2

In C#, suppose a class C1 implements Interface I1, and a class C2 is derived from C1.

  1. Generally speaking, in the definition of C2, do I need to declare that C2 implements I1?
  2. Same question, if in the declaration of C1, I1 has a type argument, and that type argument is different for C1 and for C2?

    For example,

    public abstract class C1: I1<C1>
    
    public class C2: C1, I1<C2>
    

    Do I need to write I1 in the definition of C2?

Thanks.

Tim
  • 1
  • 141
  • 372
  • 590

3 Answers3

4
  1. No. If an interface is implemented in a base class, the derived class also implements them without having to declare it explictly again.
  2. Generic interface for different generic arguments must be declared explicitly. The reason is that e.g. an IEnumerable<int> is a completely different type than an IEnumerable<string> that most probably requires the derived class to implement methods with a different signature than the base class.

Example:

public interface IGenericInterface<T> 
{
     T GetSomething();
     void DoSomething(T arg);
}

public class BaseClass : IGenericInterface<int>
{
     public virtual int GetSomething() { return 5; }
     public virtual void DoSomething(int arg) { Console.WriteLine(arg); }
}

public class Derived : BaseClass, IGenericInterface<string>
{
     string IGenericInterface<string>.GetSomething() { return "hello world!"; }
     public void DoSomething(string arg) { Console.WriteLine(arg); }
}

Note that in this example the Derived.GetSomething() needs to be implemented explicitly, because otherwise it would conflict with the base class' int version. Methods with the same name are not allowed to only differ in their return types.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • Thanks. In my example, are `I1` and `I1` both interfaces and different interfaces? Is `I1` an interface template, and not an interface? – Tim Feb 03 '17 at 05:21
  • @Tim `I1<>` is a _generic_ interface (don't mix that up with c++ _templates_, they are very different). `I1` is a specific interface (I just can't remember the correct english term for "a generic type with all generic arguments specified"). `I1` and `I1` are both specific interfaces, but they are _different_ types (you cannot assign an `I1` to a `I1` variable unless they are co-variant, but that's a topic for itself. – René Vogt Feb 03 '17 at 09:03
  • What's the definition of covariant? – Tim Feb 03 '17 at 14:34
  • @Tim As I said, it's a topic for itself that does not fit in a comment. You may a look [here](http://stackoverflow.com/questions/2033912/c-sharp-variance-problem-assigning-listderived-as-listbase) or google for "c# variance" to find a lot of good articles about that. – René Vogt Feb 03 '17 at 14:37
1

If base class implements some interface you don't have to re-implement it in derived class.

Ali Ezzat Odeh
  • 2,093
  • 1
  • 17
  • 17
1
  1. Considering the normal use case, the answer is generally no. There is however a scenario where you should declare again the interface; when you want to modify the behavior. Consider the following code:

    public interface IHello
    {
        string SayHello();
    }
    
    public class Foo : IHello
    {
        public string SayHello() => "Foo says hello!";
    }
    
    public class DerivedFoo : Foo { }
    
    public class AnotherDerivedFoo : Foo, IHello
    {
        string IHello.SayHello() => "AnotherDerivedFoo says hello!";
    }
    

    And now:

    IHello foo = new Foo();
    IHello derivedFoo = new DerivedFoo();
    IHello anotherDerivedFoo = new AnotherDerivedFoo();
    
    Console.WriteLine(foo.SayHello()); //prints "Foo says hello!"
    Console.WriteLine(derivedFoo.SayHello()); //prints "Foo says hello!"
    Console.WriteLine(anotherDerivedFoo.SayHello()); //prints "AnotherDerivedFoo says hello!" !!!
    

    Your question probably refers to Foo and DerivedFoo but a seldom known feature of the language is AnotherDerivedFoo where you basically reimplement the interface with different behavior.

    Do note however the following:

    var anotherDerivedFoo = new AnotherDerivedFoo(); //reference is typed AnotherDerivedFoo
    Console.WriteLine(anotherDerivedFoo.SayHello()); //prints "Foo says hello!"
    

    This is due to the fact that you can not reimplement the implicit implementation of the interface.

  2. Yes, you have to declare both. Do notice though that now C2 will implement both I1<C1> and I1<C2>, one does not cancel the other, they are, to all purposes, two different interfaces.

    This can cause unfortunate situations:

    public interface I1<T>
    {
        string Foo(T fooable);
    }
    
    public class C1: I1<int>
    {
        public string Foo(int i) => "C1.Foo called";
    }
    
    public class C2: C1, I1<double>
    {
        public string Foo(double d) => "C2.Foo called";
    }
    

    And now:

    var c2 = new C2();
    Console.WriteLine(c2.Foo(1)); //C2.Foo(double d) is called,
                                        //not C1.Foo(int i)!
    

    So be careful!

InBetween
  • 32,319
  • 3
  • 50
  • 90