Reputation: 398
I am wondering if the following code can be written in C#:
AbstractClass a = new ConcreteClass1();
a.Operations.Method1();
AbstractClass b = new ConcreteClass2();
b.Operations.Method2();
where Method1() is exclusive to the ConcreteClass1 instance and Method2() is exclusive to the ConcreteClass2() instance. As a result, a.Operations.Method2() and b.Operations.Method1() would be invalid.
Upvotes: 0
Views: 82
Reputation: 29212
It's okay for ConcreteClass1
and ConcreteClass2
to have some different methods, but share some functionality that they both inherit from AbstractClass
. (If you cast them as their base type then you can only call common methods that they inherit from the base type.)
It sounds like the difference between whether a concrete class uses Method1
or Method2
is an internal detail that should be handled inside the class. The class should know what method it needs to call. In fact, does a consumer of that class even need to know that it depends on Operations
? Probably not. Consumers should just call a method on the class, and then whether that class uses Operations.Method1
, Operations.Method2
, or even depends on Operations
at all is an internal implementation detail.
Maybe what you want is something like this:
public abstract class AbstractClass
{
public abstract void DoSomething();
}
public class Operations
{
public void Method1()
{
//Does something
}
public void Method2()
{
//Apparently does something comopletely different
}
}
public class ConcreteClass1 : AbstractClass
{
private Operations _operations;
public override void DoSomething()
{
_operations.Method1();
}
}
public class ConcreteClass2 : AbstractClass
{
private Operations _operations;
public override void DoSomething()
{
_operations.Method2();
}
}
Operations
should only be in the base class if it's required that every derived class will use it. (That doesn't happen too much. If all of the derived classes have the same behavior, why isn't it in the base class?) If that's the case then you can hide it in the base class, like this:
public abstract class AbstractClass
{
private Operations _operations;
protected Operations Operations { get { return _operations; } }
public abstract void DoSomething();
}
That way it's exposed to the derived classes but hidden from everything else.
Upvotes: 0
Reputation: 27095
This is not possible by design - a
and b
have the same type, and the compiler will treat them as such. The only way to make it work is by using runtime exceptions.
The concept behind using abstract classes or interfaces conflicts with what you are attempting to do; it sounds like ConcreteClass1
and ConcreteClass2
do not server the same purpose, should they still use the same abstract base class?
I don't know what exactly you are trying to do - so I'll provide a few options:
Use interfaces to show that specific classes implement specific operations:
interface IOperation1
{
void Operation1();
}
interface IOperation2
{
void Operation2();
}
Then reference the interfaces based on what you are trying to achieve.
If Method1
and Method2
are supposed to be invoked at the same time, consider a design where AbstractClass
declares the method to be invoked, and the concrete classes do different operations based on that:
abstract class AbstractClass
{
...
abstract void DoSomeOperation();
}
class ConcreteClass1
{
override void DoSomeOperation()
{
this.Operations.Method1();
}
}
class ConcreteClass2
{
override void DoSomeOperation()
{
this.Operations.Method2();
}
}
Upvotes: 1