jeudi 2 février 2017

Are there drawbacks to the generic-implementing-non-generic-interface pattern?

I'm starting to see this pattern appear often in my code:

class Foo { }

interface IBar
{
    Foo Foo { get; }
}

class Bar<TFoo> : IBar where TFoo : Foo
{
    public TFoo Foo { get; private set; }

    IBar.Foo Foo
    {
        get 
        { 
            return Foo; 
        }
    }
}

Some of its benefits are:

  1. An easy way to check whether an object is of the wrapping type (if (something is IBar))
  2. Strong-typed access to TFoo in closed-constructed Bar<>s
  3. Polymorphic access to Foo in interfaced IBars

One could argue that this kind of pattern is everywhere in the framework (e.g. List<T> : IList), but I wonder if this is just a remnant of .NET 1.0, when generics didn't exist.

Off the top of my head, my main concern is that IBar is not necessarily a proper contract that defines what members a "bar" should provide; it's only a hack to access generically typed members.

Should I be worried about spreading this pattern in my code base? If so, what alternative patterns would provide some or all of the 3 benefits listed above?

Because explicitly implementing abstract members is not allowed, this "ideal" solution is not possible:

class Foo { }

class Bar
{
    public abstract Foo Foo { get; }
}

class Bar<TFoo> : Bar where TFoo : Foo
{
    private TFoo foo;

    Bar.Foo Foo
    {
        get
        {
            return foo;
        }
    }

    public new TFoo Foo
    {
        get
        {
            return foo;
        }
    }
}

Aucun commentaire:

Enregistrer un commentaire