Patrick Skelton Ответов: 1

В 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 ) {}
}

Пока все в порядке. Теперь проблема заключается в том, что в конкретном графическом объекте (например, GraphicsSubclassB) код иногда должен ссылаться на свой конкретный связанный логический объект (LogicSubclassBПоскольку я знаю, каким должен быть тип логического объекта, я могу использовать простое приведение или as оператор. Так что я мог бы просто взять это:

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


Но есть ли способ выразить это в GraphicsBase? Есть ли способ выразить, что каждый подкласс GraphicsBase необходимо обеспечить собственную реализацию StronglyTypedLogicObject собственность?

Что я уже пробовал:

Единственный способ, которым я могу думать, что это может сработать, - это использовать дженерики, что-то вроде следующего (что не компилируется)...

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;
}

1 Ответов

Рейтинг:
12

F-ES Sitecore

Попробуйте что-нибудь вроде

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) { }
}


Patrick Skelton

Господи! Легко, когда знаешь как! Большое спасибо.

Patrick Skelton

@F-ES Sitecore у меня явно нет твердого понимания этого. Я могу понять, почему следующий код не будет компилироваться, но часть меня чувствует, что мне не хватает ключевого кирпича здесь. публичный статический класс GraphicsFactory
{
public static GraphicsBase<logicbase> Create( string whichOne )
{
возврат нового GraphicsSubclassB( new LogicSubclassB() );
}
}

Ошибка: не удается неявно преобразовать GraphicsSubclassB в GraphicsBase<logicbase>.

F-ES Sitecore

Вы действительно не можете привести универсальные классы к другим универсальным классам, вам, возможно, придется подумать о том, как вы собираетесь использовать это. Имея в виду что ваш вызывающий код не будет знать какой конкретный класс LogicBase вы используете он может работать только на уровне LogicBase поэтому ваша Фабричная логика может работать следующим образом

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


вместо того чтобы получать базовый объект graphics, просто верните логический объект. Или вы можете создать новый объект generate graphicsbase

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


тогда фабрика была бы

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


Ваше призвание могло бы быть

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


и хотя строго типизированное свойство возвращает LogicBase, объект на самом деле является LogicSubclassB, так что вы можете перейти к нему в своем вызывающем коде, если это необходимо, и любой виртуальный метод тоже должен работать.