Reputation: 3851
Maybe this is a dumb question. But, I don't get the point what I am missing.
Given the following class-definition
public abstract class AbstractBaseClass
{
public abstract void Create(AnotherAbstractClass param1);
}
Wheras AnotherAbstractClass
is defined
public abstract class AnotherAbstractClass
{
}
with a concrete implementation
public class AnotherConcreteImplementation : AnotherAbstractClass
{
}
I want to be able to have the override of the Create
method to use a concrete type:
public class ConcreteImplementation : AbstractBaseClass
{
public override void Create(AnotherConcreteImplementation param1) <-- There is no suitable method for override
{
// param1 is an instance of the concrete implementation
}
public override void Create(AnotherAbstractClass param1) <-- this is working but I'll have to cast on each implementation
{
// param1 is an instance of the abstract class and needs a cast
}
}
Is this simply not possible or is there some way I'm not aware of? Maybe using generics?
Edit #1 (added more context)
I'm trying to achieve/enforce that in a concrete implementation there is only one parameter valid.
Think of it like it's a database-layer. The Create
method will create a new entry in the database. As of each table has different values, the create-parameter also has.
The casting inside smells (in my opinion) as of it can be called with any concrete implementation of AnotherAbstractClass
.
public class AddressTable : AbstractBaseClass
{
public override void Create(AnotherAbstractClass param1)
{
// cast to concrete instance
var casted = (ConcreteAddressCreate)param1;
}
}
public class CityTable : AbstractBaseClass
{
public override void Create(AnotherAbstractClass param1)
{
// cast to concrete instance
var casted = (ConcreteCityCreate)param1;
}
}
Having an instance of AddressTable
I can call
addressIntance.Create(new ConcreteAddressCreate()); // would be okay
on the other hand I can call it
addressIntance.Create(new ConcreteCityCreate()); // would be okay but will fail at runtime with InvalidCastException
Edit #2 (additional info)
It should also be possible to extend the AbstractBaseClass
class with more abstract methods later.
So, for me it's more likely to have generic methods instead of an concrete class-implemenation with 200 generic parameters for each method to implement.
Upvotes: 2
Views: 1343
Reputation: 151740
Yes, you can do that using generics:
public abstract class AbstractBaseClass<T>
where T : AnotherAbstractClass
{
public abstract void Create(T param1);
}
public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
public override void Create(AnotherConcreteImplementation param1)
{
}
}
Upvotes: 2
Reputation: 12691
Generics is indeed the way to do it.
public abstract class AbstractBaseClass<TDerivedClass> where TDerivedClass : AnotherAbstractClass
{
public abstract void Create(TDerivedClass param1);
}
And then you can do:
public class ConcreteImplementation : AbstractBaseClass<AnotherConcreteImplementation>
{
public override void Create(AnotherConcreteImplementation param1) // Works because TDerivedClass = AnotherConcreteImplementation
{
...
}
}
Upvotes: 0
Reputation: 276596
It violates the Liskov Substitution Principle so it makes perfect sense you can't do this. Namely, you can't just "have" covariance like this for free:
AbstractBaseClass bcl = new ConcreteImplementation();
bcl.Create(new DifferentImplementationWithoutSecondAbstract());
The contract AbstractBaseClass defines makes Create
have to work with any implementation of AbstractBaseClass
passed in - if you give a constraint on what can be passed in you've violated the contract it defines.
Like you assumed - you can use generics:
// notice the recursive definition, we require the generic parameter
// to be a generic parameter of itself - allowing AbstractBaseClass
// to not be aware of its subclasses like in the other answers.
public abstract class AbstractBaseClass<T> where T : AbstractBaseClass<T>
{
public abstract void Create(T param1);
}
public class Concrete : AbstractBaseClass<Concrete>
{
public override void Create(Concrete param1)
{
Console.WriteLine("Hello!");
}
}
Upvotes: 2