1

what I want is that if class A implements my interface (B) I also want A being forced to implement an interface/type derived from type C.

In code, the result would look like this:

public interface SomeInterface
{
    // implementing this interface forces the implementing class to also implement
    // a derived interface/type of SomeBaseInterface 
    void SomeMethod();
}

public interface SomeBaseInterface
{
    void SomeBaseMethod();
}

public interface SomeOtherInterface : SomeBaseInterface
{
    void SomeOtherMethod();
}

public class ImplementingClass : SomeInterface, SomeOtherInterface // <- if not
 // implementing an interface/type derived from SomeBaseInterface
 // this should not compile
{
    public void SomeMethod()
    {
    }

    public void SomeOtherMethod()
    {
    }

    public void SomeBaseMethod()
    {
    }
}

*edit it would also work to 'mark' SomeBaseInterface as not inheritable by a class. Meaning that only another interface/abstract class can inherit from it. not possible, see C# Interfaces- only implement an interface in other interfaces

Community
  • 1
  • 1
Steffen Winkler
  • 2,805
  • 2
  • 35
  • 58
  • It looks a bit like you're going to end up with the sort of hierarchy spelt out in Eric Lippert's [Curiouser and Curiouser post](http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx). Note the bold warning towards the end. – Damien_The_Unbeliever May 14 '14 at 07:13
  • Is there a reason you can't derive SomeInterface from SomeBaseInterface? It's only compile-time way to force to implement both. – Adriano Repetti May 14 '14 at 07:13
  • 1
    @Adriano yeah, just clarified. ImplementingClass needs to implement a type derived from SomeBaseInterface. Not SomeBaseInterface directly. – Steffen Winkler May 14 '14 at 07:14
  • @Damien_The_Unbeliever that's interesting but there is one thing missing: What I would want is something like `class Cat : Animal` and `Cat` then being forced to implement `Feline` – Steffen Winkler May 14 '14 at 07:22
  • What's wrong with having `Feline: Animal` and then `Cat: Feline`? – Sergey Krusch May 14 '14 at 08:03
  • @SergeyKrusch there is nothing 'forcing' Cat to implement Feline instead of Animal. – Steffen Winkler May 14 '14 at 08:17
  • Really? Cat is forced to implement both interfaces this way (namely Animal and Feline). – Sergey Krusch May 14 '14 at 08:21
  • @SergeyKrusch I think I lost track somewhere...could you hack up some mock up code? Because I'm not seeing how Cat is forced to implement Animal *and* Feline. – Steffen Winkler May 14 '14 at 08:52
  • See my answer. It is not, exactly, an answer to your question. But I think you are trying to do something, that you will regret of later. – Sergey Krusch May 14 '14 at 09:10
  • @SergeyKrusch * that you will regret of later.* add it to the list ;) – Steffen Winkler May 14 '14 at 09:35

3 Answers3

1

I don't think you can force the use of one interface when using another, unless you derive one interface from the other. However, you could use attributes and set up a unit test that would check your code for you.

[MyInterfaceCheck(typeof(IMyBaseInterface))]
public interface IMyInterfaceA {...}

public interface IMyBaseInterface {...}

public interface IMyInterfaceB : IMyBaseInterface {...}

public class MyClass : IMyInterfaceA, IMyInterfaceB {...}

The attribute would be defined simply as:

public class MyInterfaceCheckAttribute : Attribute
{
    public MyInterfaceCheckAttribute(Type typeThatShouldAlsoBeInherited)
    {
        if (!typeThatShouldAlsoBeInherited.IsInterface)
        {
            throw new ArgumentException("Incorrect type being used with MyInterfaceCheckAttribute.");
        }
        TypeThatShouldBeInherited = typeThatShouldAlsoBeInherited;
    }

    public Type TypeThatShouldBeInherited { get; private set; }
}

And the Unit Test:

[TestMethod]
public void CheckInterfaceInheritenceTest()
{
    Dictionary<Type, MyInterfaceCheckAttribute> typesToCheck = new Dictionary<Type, MyInterfaceCheckAttribute>();
    foreach (Type typeToCheck in Assembly.GetExecutingAssembly().GetTypes())
    {
        MyInterfaceCheckAttribute myAtt = typeToCheck.GetCustomAttribute(typeof(MyInterfaceCheckAttribute), true) as MyInterfaceCheckAttribute;
        if (myAtt != null)
        {
            typesToCheck.Add(typeToCheck, myAtt);
        }
    }

    foreach (Type typeToCheck in Assembly.GetExecutingAssembly().GetTypes())
    {
        Type[] interfaces = typeToCheck.GetInterfaces();

        foreach (KeyValuePair<Type, MyInterfaceCheckAttribute> kvp in typesToCheck)
        {
            if (interfaces.Contains(kvp.Key) && !interfaces.Contains(kvp.Value.TypeThatShouldBeInherited))
            {
                Assert.Fail("The type " + typeToCheck.Name + " should inherit the interface " + kvp.Value.TypeThatShouldBeInherited.Name);
            }
        }
    }
}
Ben
  • 3,241
  • 4
  • 35
  • 49
1

The obvious way would be to have SomeInterface : SomeBaseInterface and have ImplementingClass : SomeInterface, SomeOtherInterface. Can you clarify why it is not a possibility? This forces the class implementing SomeInterface to at least inherit from SomeBaseInterface and this can be extended by additionally by inheriting from SomeOtherInterface.

The only difference is that it's possible to no inherit SomeOtherInterface, but for all you know that interface could contain nothing anyway.

EmptyInterface:

interface SomeOtherOtherInterface : SomeBaseInterface {
}

I would suggest if your wanting to allow the class to inherit from the above interface and not SomeBaseInterface you're doing something wrong. Also the implication is that your specifying for the existence of more unknown methods, which also is a touch suspicious.

Is it that there are things you should have put in SomeBaseInterface but didn't? Is there, for example, a void SendEmail in one derived interface and a void SendFax in another when clearly something like SendMessage should have been in SomeBaseInterface all along?

But obviously, if you want to proceed anyway use the unit testing approach.

Nathan Cooper
  • 6,262
  • 4
  • 36
  • 75
  • uhm. I've a BaseInterface from which most 'modules' (MEF) are inheriting. It forces all modules to have a config, a name...stuff like that. Now, I've different kinds of modules. Some are, for example, UserInterfaces. Some are for pushing informations into a database, some just 'do stuff'. I grouped all those modules. Meaning that for each group (database, UI...) there is one 'Parent' module managing the 'child' modules. Each module group has one interface defining it and that is derived from the Base interface. Each parent should implement the Parent interface and a group interface. – Steffen Winkler May 14 '14 at 09:32
  • Right, right. It may be something you can't enforce then, after all hypothetically speaking its not your responsibility to make sure derived classes make sense. But have you considered the possibility someone may make `ImplementingClass` abstract and inherited by both your database and UI classes? I think maybe just comment in what the class is for and if someone wants to make a class that uses `SomeInterface` but doesn't usefully interact with any of your systems, let them or unit test against it (as per the accepted answer). – Nathan Cooper May 14 '14 at 11:30
  • 1
    I already wrote a comment in there ;). I also figured out how to make comments visible inside another project (pesky xml files). So that's covered ;). – Steffen Winkler May 14 '14 at 14:08
0

Just to make it clear about inheritance and interfaces. Let's assume that we have interfaces IAnimal and IFeline:

interface IAnimal
{
    void Eat();
}

interface IFeline: IAnimal
{
    void Purr();
}

Now let's define class Cat and require it to implement interface IFeline:

class Cat: IFeline
{

}

Compiling the code:

'Cat' does not implement interface member 'IFeline.Purr()'
'Cat' does not implement interface member 'IAnimal.Eat()'

And now it is clear that compiler expects us to implement both interfaces IAnimal and IFeline in class Cat.

Sergey Krusch
  • 1,928
  • 16
  • 17
  • correct. But there is nothing preventing Cat from just implementing IAnimal. – Steffen Winkler May 14 '14 at 09:27
  • Do you mean, nothing is preventing from writing `class Cat: IAnimal`? – Sergey Krusch May 14 '14 at 09:34
  • correct. See the striked text in my question for further detail. – Steffen Winkler May 14 '14 at 09:36
  • Hm... I see. But why do you want this? What will happen if someone will have, let's say `Wombat: IAnimal`? – Sergey Krusch May 14 '14 at 09:40
  • well, that'd mean that a Wombat is just an animal. It has the generic functions of an animal but it actually can't do anything aside from that. So it won't be a Wombat. For example all `Feline`s have the ability to Hunt and use scratch posts and they are able to use their retractable claws. A Wombat derived from IAnimal on the other hand wouldn't be able to dig/build their tunnelsystems or 'crush' a foe against the roof of their tunnel. Sidenote: You just made me explain to my boss why I was reading a wikipedia article about wombats...that's a new one ;) – Steffen Winkler May 14 '14 at 10:06
  • :D Well, actually, it is you, who decide what `Wombat` can do. And it doesn't really matters whether you write `class Wombat: IAnimal` or `class Wombat: IVombatidae` (with defining `interface IVombatidae: IAnimal`) until you actually have some code that knows about `IVombatidae`. – Sergey Krusch May 14 '14 at 10:42
  • Don't you want to break Liskov substitution principle? I.e. you expect `IAnimal` to do something that isn't explicitly stated in the interface (which is bad). – Sergey Krusch May 14 '14 at 10:45
  • not really. I want to define that an Animal has to be a specific Animal inside the Animal interface. Also all my modules are only 'interacting' with eachother via those interfaces. So if it's not defined in an interface, it doesn't exist. – Steffen Winkler May 14 '14 at 11:16