Reputation: 1051
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
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
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
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
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
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
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
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
Reputation: 16032
You cannot do this. The only option is to rearrange your classes.
Upvotes: 0
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