Reputation: 21
I am looking at a complex and generic legacy framework which I will eventually need to extend, first up however is to simply understand it, and I'm struggling to do so due to the inheritence hierarchy and structure.
This all forms part of the inner workings of a WCF services stack, handling the requests, responses, etc.
I've included only the class signatures and their constructors as a sample as the inner functionality is of no concern.
public sealed class ProcessDerived : ProcessBase<Filter, RequestExternal, RequestItemExternal, ResponseCallBack, ResponseInternal>
{
public ProcessDerived(ProcessManager Manager) : base(Manager) { }
}
public abstract class ProcessBase<TFilter, TRequestExternal, TRequestItemExternal, TResponseCallBack, TResponseInternal>
: ProcessBaseSync<TFilter, TRequestExternal, TRequestItemExternal, TResponseCallBack, TResponseInternal>
where TFilter : FilterBase
where TRequestExternal : class
where TRequestItemExternal : class
where TResponseCallBack : class
where TResponseInternal : ProcessResponseBase
{
protected ProcessBase(ProcessManager Manager) : base(Manager) { }
}
public abstract class ProcessBaseSync<TFilter, TRequestExternal, TRequestItemExternal, TResponseCallBack, TResponseInternal>
: ProcessBaseCache<TFilter, TRequestExternal, TRequestItemExternal, object, TResponseCallBack, TResponseInternal, CacheKeyBase>
where TFilter : FilterBase
where TRequestExternal : class
where TRequestItemExternal : class
where TResponseCallBack : class
where TResponseInternal : ProcessResponseBase
{
protected ProcessBaseSync(ProcessManager Manager) : base(Manager) { }
}
public abstract class ProcessBaseCache<TFilter, TRequestExternal, TRequestItemExternal, TResponseImmediate, TResponseCallBack, TResponseInternal, TCacheKey>
: IProcess, IProcess<TFilter, TResponseInternal>, IProcess<TResponseCallBack>
where TFilter : FilterBase
where TRequestExternal : class
where TRequestItemExternal : class
where TResponseImmediate : class
where TResponseCallBack : class
where TResponseInternal : ProcessResponseBase
where TCacheKey : CacheKeyBase
{
private ProcessManager _manager;
protected ProcessBaseCache(ProcessManager Manager)
{
_manager = Manager;
}
}
The main questions I have:
1) What is the technical term used to describe this multiple inheritence structure, like seen on the first line: "ProcessDerived : ProcessBase".
It reminds me of tuples, but I don't understand whats happening here on a technical level. Is this just a way to get around the multiple inheritence limitation?
2) Does it inherit from "ProcessBase" as well as all the type parameters next to it?
3) What is the purpose of adding ": base(XYZ)" to the constructor? Is this simply a requirement to match the class inheritence (constructor mimicking the class signature)? I don't understand why this is required.
This complex 4-tier hierarchy seems very unecessary and feels impossible to follow.
I'm clearly missing some fundamental C# knowledge here.
Upvotes: 0
Views: 65
Reputation: 42350
1) What is the technical term used to describe this multiple inheritence structure, like seen on the first line: "ProcessDerived :
ProcessBase
.
That's single inheritance. ProcessDerived
inherits from ProcessBase<Filter, RequestExternal, RequestItemExternal, ResponseCallBack, ResponseInternal>
.
2) Does it inherit from "ProcessBase" as well as all the type parameters next to it?
ProcessBase<Filter, RequestExternal, RequestItemExternal, ResponseCallBack, ResponseInternal>
is a (closed generic) type. ProcessDerived inherits from it.
ProcessBase<TFilter, TRequestExternal, TRequestItemExternal, TResponseCallBack, TResponseInternal>
is the corresponding open generic type -- the type parameters TFilter
etc haven't yet been specified.
3) What is the purpose of adding ": base(XYZ)" to the constructor? Is this simply a requirement to match the class inheritence (constructor mimicking the class signature)? I don't understand why this is required.
When you subclass is instantiated, it needs to call one of the base class's constructors. If the base class has a parameterless constructor, this is called implicitly. If it doesn't, you need to explicitly call one of its constructors, passing all necessary parameters, using : base(...)
.
I'm clearly missing some fundamental C# knowledge here.
I suspect the knowledge you're missing is around generics - you seem to think that generic types, and generic type parameters, are involved in inheritance.
Upvotes: 0
Reputation: 66509
To answer your first (and second) question, you can extend a single base class and then implement several interfaces, but the code you posted only extends a single base class. It just happens that ProcessBase
accepts 5 different types, but it's still one class.
As for your third question, they added base
because the class extends a base class that doesn't have a parameterless constructor.
Here's a simpler example demonstrating the same concept. The Person
class has a single ctor expecting a name, so any class that extends it must provide that parameter via a call to base()
.
public class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name;
}
}
public class Employee : Person
{
public DateTime HireDate { get; set; }
public Employee(string name, DateTime hireDate) : base(name)
{
HireDate = hireDate;
}
}
Upvotes: 1