Matt Thomas Matt Thomas - 2 months ago 9
C# Question

Possible to cast to interface that isn't inherited?

Why isn't it possible to cast an instance of:

sealed class Foo
{
public void Go() { }
}


...to this interface:

interface IBar
{
void Go();
}


...even though
Foo
has the signature of
IBar
?

How can I turn an instance of
Foo
into an
IBar
? Assume I have no control over
Foo
.

Dai Dai
Answer

No, C# does not support duck-typing.

The OOP-approach to this problem is to use the Adapter Pattern.

You would do this:

class FooBarAdapter : IBar {

    private readonly Foo foo;

    public FooBarAdapter(Foo foo) {

        this.foo = foo;
    }

    public void Go() {

        this.foo.Go();
    }
}

Whenever you have a Foo but need an IBar you wrap it on-demand:

public void ContrivedScenario() {

    Foo foo = GetFooFromExternalDependency();

    FooBarAdapter adapter = new FooBarAdapter( foo );

    this.NeedsIBar( adapter );
}

public void NeedsIBar(IBar bar) { ... }

I note that if Foo-to-IBar conversion happens a lot, you can make use of implicit conversions, so you don't need to explicitly construct FooBarAdapter instances, but it is debatable if this is good software engineering practice or not:

class FooBarAdapter : IBar {

    // (same as above)

    public static implicit operator FooBarAdapter(Foo foo) {
        return new FooBarAdapter( foo );
    }
}

That way you can do this:

public void ContrivedScenario() {

    Foo foo = GetFooFromExternalDependency();

    this.NeedsIBar( foo ); // the conversion from `Foo foo` to `FooBarAdapter` happens implicitly
}

One reason why C# doesn't support duck-typing is because just because a class's interface (in the OOP sense, not a literal interface) shares the same identifiers as another, doesn't mean they're compatible. For example Process.Kill (kills the process) and MegaDeathKillBot3000.Kill (kills all humanity) probably shouldn't be used interchangeably... unless you really want to.

Comments