Click here to Skip to main content
15,881,763 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Apologies for the vague nature of the question. I couldn't think of a concise way to explain the problem I seem to be facing for the Nth time and which I think must be an extremely common scenario. Code explains it best...

C#
abstract class LogicBase {}
class LogicSubclassA : LogicBase{}
class LogicSubclassB : LogicBase{}

abstract class GraphicsBase
{
	public GraphicsBase( LogicBase logicObject ) => LogicObject = logicObject;
	public LogicBase LogicObject { get; private set; }
}

class GraphicsSubclassA : GraphicsBase
{
	public GraphicsSubclassA( LogicBase logicObject ) : base( logicObject ) {}
}

class GraphicsSubclassB : GraphicsBase
{
	public GraphicsSubclassB( LogicBase logicObject ) : base( logicObject ) {}
}

All okay so far. Now the problem is that in a concrete graphics object (e.g. GraphicsSubclassB) code sometimes needs to refer to its specific associated logic object (LogicSubclassB). Since I know what the type of the logic object is supposed to be, I can use a straightforward cast or the as operator. So I could simply have this:

class GraphicsSubclassB : GraphicsBase
{
	public GraphicsSubclassB( LogicBase logicObject ) : base( logicObject ) {};
	public LogicSubclassB StronglyTypedLogicObject => (LogicSubclassB)LogicBase;
}


But is there a way to express this in GraphicsBase? Is there a way to express that each subclass of GraphicsBase must provide its own implementation of the StronglyTypedLogicObject property?

What I have tried:

The only way I can think this might work is using generics, something like the following (which does not compile)...

C#
abstract class GraphicsBase<T> where T : LogicBase
{
	public GraphicsBase( LogicBase logicObject ) => LogicObject = logicObject;
	public LogicBase LogicObject { get; private set; }
	public virtual T StronglyTypedLogicObject => LogicObject;
}

class GraphicsSubclassB<T> : GraphicsBase<LogicSubclassB>
{
	public GraphicsSubclassB( LogicBase logicObject ) : base( logicObject ) {}
	public override T StronglyTypedLogicObject => (T)LogicObject;
}
Posted
Updated 21-Oct-20 0:19am

1 solution

Try something like

C#
public abstract class GraphicsBase<T> where T : LogicBase
{
    public GraphicsBase(T logicObject) => StronglyTypedLogicObject = logicObject;
    public LogicBase LogicObject => StronglyTypedLogicObject;
    public virtual T StronglyTypedLogicObject { get; private set; }
}

public class GraphicsSubclassB : GraphicsBase<LogicSubclassB>
{
    public GraphicsSubclassB(LogicSubclassB logicObject) : base(logicObject) { }
}
 
Share this answer
 
Comments
Patrick Skelton 21-Oct-20 6:54am    
Jeez! Easy when you know how! Thank you very much.
Patrick Skelton 23-Oct-20 6:26am    
@F-ES Sitecore I clearly haven't got a solid understanding of this. I can sort-of see why the following code won't compile, but part of me feels like I'm missing a key brick here. public static class GraphicsFactory
{
public static GraphicsBase<logicbase> Create( string whichOne )
{
return new GraphicsSubclassB( new LogicSubclassB() );
}
}

Error: Can't implicitly convert GraphicsSubclassB to GraphicsBase<logicbase>.
F-ES Sitecore 23-Oct-20 8:14am    
You can't really cast generic classes to other generic classes, you might need to think about how you're going to use this. Bearing in mind your calling code isn't going to know which concrete LogicBase class you're using it can only work on the LogicBase level so your factory logic could work like this instead

public static class LogicBaseFactory{    public static LogicBase Create(string whichOne)    {        return new LogicSubclassB();    }}


rather than getting the graphics base object just return the logic object instead. Or you could create a new generate graphicsbase object

public class GraphicsSubclass : GraphicsBase<LogicBase>{    public GraphicsSubclass(LogicBase logicObject) : base(logicObject) { }}


then the factory would be

public static class GraphicsFactory{    public static GraphicsSubclass Create(string whichOne)    {        return new GraphicsSubclass(new LogicSubclassB());    }}


Your calling could would be

GraphicsSubclass g = GraphicsFactory.Create("b");


and while the strongly typed property returns LogicBase, the object is actually LogicSubclassB so you can upcast to that in your calling code if needed, and any virtual method should work too.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900