Search code examples
c#marker-interfaces

Marker interfaces: make them inter-castable


I have three marker interfaces for a fluent API's extension methods:

interface IOne { }
interface ITwo { }
interface IOneOrTwo : IOne, ITwo { }

and the following extension method:

public static IOneOrTwo Foo (this IOne obj, string arg)
{
    // do something with arg
    return obj; // <- possible without cast?
}

Question: is it somehow possible to return obj without casting? Normally you need to explicitly downcast in this situation, however, none of those interfaces is requiring the underlying object to have any sort of method/property/whatsoever.

Note: The actual implementation class implements all of the interfaces.

Question 2: Why is implementing IOne and ITwo not automatically let the implementation be also of type IOneOrTwo?


Solution

  • is it somehow possible to return obj without casting?

    No. Just because a class implements IOne does NOT mean it also implements IOneOrTwo. So you need to cast (which may well fail)

    none of those interfaces is requiring the underlying object to have any sort of method/property/whatsoever.

    That's irrelevant. The lack of actual methods does not magically let you down-cast. If an object implements IOne, technically it could implement IOneOrTwo without adding any methods, but it still would need to explicitly include that in the class definition.

    Why is implementing IOne and ITwo not automatically let the implementation be also of type IOneOrTwo

    Because IOneOrTwo could include methods that are not part of IOne or ITwo. Just because an object implements IOne and ITwo does not mean it also implements any interface that also includes those two.

    You could get what you want using generics:

    public static T Foo<T> (this T obj, string arg) where T: IOne
    {
        // do something with arg
        return obj; 
    }
    

    then you could say:

    IOneOrTwo obj = new IOneOrTwoImpl();
    IOneOrTwo obj2 = obj.Foo("gfgfd");  // valid since obj implements IOneOrTwo
    

    but you can't do:

    IOne obj = new IOneImpl();
    IOneOrTwo obj2 = obj.Foo("gfgfd");  // not valid since obj does not implement IOneOrTwo
    

    without a cast.

    Bottom line - interface implementations must be explicitly declared. Just because a class can implement an interface (meaning it contains all of the methods/properties that make up that interface) doesn't mean you can treat it as if it does implement that interface.