bryan
bryan

Reputation: 1051

C#: Possible to not implement a protected internal abstract on an abstract class?

what do I need to change in my abstract base so that the implementations don't have to implement BOTH methods when only one is needed in any given scenario? My example is:

internal abstract class BaseBar<T> where T : BaseThing
{
    protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes);
    protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames);
}

class FooBarMapper : BaseBar<FooData>
{
    protected internal override SforceObjectValueData DataObjectFromXmlElements(IEnumerable<XmlNode> nodes)
    {
        throw new NotImplementedException();
    }

    protected internal override FooData DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames)
    {
        FooData o = new FooData
        {
            bar1 = bar1,
            bar2 = bar2
        };
        return o;
    }
}

Cheers.

edit: The design is weird/bad/stupid I know...I'm working with legacy code and time is not on my side right now for a refactor. I'm trying to add the second method with the string array.

Upvotes: 4

Views: 1442

Answers (9)

Jonathan
Jonathan

Reputation: 21

You could also encapsulate the parameters for DataFromXmlElements in a class and then inspect the contents of the class in an elegant way when you write the implementation...

Upvotes: 2

hunter
hunter

Reputation: 63512

I'm guessing you're going to need 2 or 3 abstract classes to achieve this

public interface BaseBar1<T> // does one
public interface BaseBar2<T> // does the other
public interface BaseBar3<T> // does both

you could use an Optional parameter

internal abstract class BaseBar<T> where T : BaseThing
{
    protected internal abstract T DataFromXmlElements(
        IEnumerable<XmlNode> nodes, string[] fieldNames);
}

class FooBarMapper : BaseBar<FooData>
{
    protected internal override FooData DataFromXmlElements(
        IEnumerable<XmlNode> nodes, 
        [Optional] string[] fieldNames)
    {
        if (fieldNames == null) // skip stuff
        else // do stuff
    }

More on the Optional Attribute.

Upvotes: 1

Gerald Davis
Gerald Davis

Reputation: 4549

Not possible.

You could however have a single abstract internal base class and then two abstracts classes (each with a single abstract method) derived from that.

Finally you would derive the working class from EITHER of the abstracted classes and thus implement the respective single method.

That "would" work but the larger question is "should" you do it? I think you may want to reconsider your implementation.

Upvotes: 1

batwad
batwad

Reputation: 3655

Either virtual default implementations as Colin Mackay said, or use interfaces and explicit implementation to stop the methods being called externally.

internal interface IBaseBar1<T> where T : BaseThing
{
    T DataFromXmlElements(IEnumerable<XmlNode> nodes);
}

interface IBaseBar2<T> where T : BaseThing
{
    T DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames);
}

class FooBarMapper : IBaseBar2<FooData>
{
    FooData IBaseBar2<FooData>.DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames)
    {
        FooData o = new FooData
        {
            bar1 = bar1,
            bar2 = bar2
        };
        return o;
    }
}

Upvotes: 1

StriplingWarrior
StriplingWarrior

Reputation: 156459

It's not really clear what you're hoping to do, exactly. What do you expect to happen if the first method gets called? Depending on what you expect, you could make the parent abstract class implement the first method based on the assumption that the second has been implemented:

protected internal T DataFromXmlElements(IEnumerable<XmlNode> nodes) {
    return DataFromXmlElements(nodes, null);
}

Upvotes: 1

Ozzy
Ozzy

Reputation: 1730

An abstract member MUST be implemented, so I guess there is no way around.

Another solution would be to define two interfaces instead, each one containing one of the members to implement. Then the implementing classes can implement one - or both - interfaces.

For example:

public interface BaseBarA<T> where T : BaseThing{
  protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes);  
}

public interface BaseBarB<T> where T : BaseThing{
  T DataFromXmlElements(IEnumerable<XmlNode> nodes, string[] fieldNames);  
}

Upvotes: 1

Colin Mackay
Colin Mackay

Reputation: 19175

You could make one or both virtual and provide default implementations that calls the other with default parameters (or without passing through the values, depending on which way around you put it).

However, I suspect your design may really require a little more of a rethink because callers will likely have a reference to the base (your abstract class) and won't know they are calling a specific derived version, in which case the calling code should always be free to call which ever method it likes.

Upvotes: 1

Andrew Bezzub
Andrew Bezzub

Reputation: 16032

You cannot do this. The only option is to rearrange your classes.

Upvotes: 0

Stormenet
Stormenet

Reputation: 26468

Maybe this works out for you?

internal abstract class BaseBar<T> where T : BaseThing
{
    protected internal abstract T DataFromXmlElements(IEnumerable<XmlNode> nodes, params string[] fieldNames);
}

Upvotes: 3

Related Questions