简体   繁体   中英

Is this a good way to expose generic base class methods through an interface?

I am trying to provide an interface to an abstract generic base class. I want to have a method exposed on the interface that consumes the generic type, but whose implementation is ultimately handled by the classes that inherit from my abstract generic base.

However I don't want the subclasses to have to downcast to work with the generic type (as they already know what the type should be).

Here is a simple version of the only way I can see to get it to work at the moment.

public interface IFoo
{
    void Process(Bar_base bar);
}

public abstract class FooBase<T> : IFoo 
    where T : Bar_base
{
    abstract void Process(T bar);

    // Explicit IFoo Implementation
    void IFoo.Process(Bar_base bar)
    {
        if (bar == null) throw new ArgumentNullException();

        // Downcast here in base class (less for subclasses to worry about)
        T downcasted_bar = bar as T;
        if (downcasted_bar == null)
        {
            throw new InvalidOperationException(
                          string.Format("Expected type '{0}', not type '{1}'",
                                        T.ToString(), bar.GetType().ToString());
        }

        //Process downcasted object.
        Process(downcasted_bar);            
    }

}

Then subclasses of FooBase would look like this...

public class Foo_impl1 : FooBase<Bar_impl1>
{
     void override Process(Bar_impl1 bar)
     {
         //No need to downcast here!
     } 
}

Obviously this won't provide me compile time Type Checking, but I think it will get the job done...

Questions:
1. Will this function as I think it will?
2. Is this the best way to do this?
3. What are the issues with doing it this way?
4. Can you suggest a different approach?

Thanks!


Edit: In Response to many answers, It is a requirement that IFoo is not Generic. I need to be able to manipulate a collection of IFoo objects regardless of the generic Types they use.


Edit: In an effort to clarify the reasoning for this...

Bar_base contains a reference to type IFoo. And must call the process method to validate the data it contains. Think of IFoo as an object that contains validation logic for the Bar_base derived objects. When the validity of Bar_base object is questioned, it calls Process on its IFoo reference to validate itself.

The reason IFoo can't be generic is that I need to be able to reference a collection of IFoo independent of the Bar_base classes.

I am going to try the approach of having two interfaces a Generic one that contains the Process method, and non-generic one that doesn't.

In the case where IFoo cannot be generic, it's very typical in a case like this to have two interfaces, IFoo<T> and IFoo, where IFoo uses the most base class supported. Think IEnumerable<T> and IEnumerable. The non-generic version is usually hidden as an interface overload, so it only comes into play when accessing the class via the non-generic interface.

Given your constraint that T is of type Bar_base, and (in your example) only using T for Process(T bar), I'm not sure why you're using generics at all. If

abstract Process(Bar_base bar)

is all you need, then that should be sufficient for class overriding with

void override Process(Bar_impl1 bar)

and your abstract class Bar_base is a sufficient type constraint.

Unless I'm missing something....

Another useful trick is to provide both generic and non-generic interface definitions, where the non-generic provides non-generic access methods and properties, and the generic interface provides only the additional methods and/or properties that requires a generic type. Clients can specify either interface, depending on whether they're in a position to share the generic type.

interface IFoo
{
...
}

interface IFoo<T> : IFoo where T : Bar_base
{
...
}

But I'm not sure that this would satisfy your needs in this case.

You could just make IFoo generic:

public interface IFoo<T> where T : Bar_base
{
    void Process(T bar);
}

Any reason you don't just use a generic interface:-

public interface IFoo<T>
  where T:Bar_base
{
    void Process(T bar);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM