Странный вопрос здесь - что-то, что возникает из-за среды, в которой я работаю.
Немного предисловия:
Я собираюсь злоупотребить известными абстракциями из таксономического ранга, чтобы описать ситуацию, с которой я застрял - проектными решениями, которые не были моими, а теперь используются в реальных системах обработки данных с высокой нагрузкой.
Я работаю над использованием (использованием) API, который был разработан другими на работе, у меня нет входных данных, и мне просто нужно иметь возможность писать код против.
Этот API фактически автоматически генерирует код C #, который был скомпилирован, и определяет сложную систему типов интерфейса, которая описывает
1 Интерфейс верхнего уровня, сотни интерфейсов второго уровня и сотни интерфейсов третьего уровня с соотношением 1: 1 на интерфейсах второго уровня и интерфейсах третьего уровня - IE, для каждого интерфейса второго уровня это ровно 1 интерфейс третьего уровня, который также явно реализует интерфейс второго уровня и интерфейс верхнего уровня.
Я опишу мою головоломку (грубо), используя первые 3 ранга в области таксономической системы рангов биологии.
Шаблон, который я буду использовать здесь:
I%Domain%
Является своего рода обобщенной заглушкой, указывающей на набор интерфейсов некоторого произвольного домена (IArchaea, IBacteria, IEukarya). Это может быть любой из этих трех (а на самом деле их буквально сотни).
I%Kingdom%
Является своего рода обобщенной заглушкой (похожей на I%Domain%
), которая, если I%Domain%
на самом деле IEukarya, будет содержать шаблоны, подобные IFungi, IProtista, IPlantae, IAnimalia. Метафора здесь разрушается, так как в действительности существует ровно 1 интерфейс этого третьего уровня, который напрямую связан с известным интерфейсом второго уровня. Однако для целей продвижения это на самом деле неважно - я просто указываю на несоответствие метафоры.
// Implemented, and "Cement". Our algorithm fundamentally works with
// IOrganism as the main type for everything, using reflection to
// iterate properties, due to the needs presented.
// Consider to be Tier-1 Interface.
interface IOrganism { /*...*/ }
// Implemented, and "Nebulous" (Could be IArchaea, IBacteria, IEukarya, etc...)
// Will never actually be IDomain, but will rather be one of
// IArchaea, IBacteria, IEukarya, in a more "generic" approach.
// Note: The %Domain% syntax is *is indicative of a
// "stub" for any arbitrary pre-defined Domain-like
// interfaces. See the pattern described above.
// Consider to be Tier-2 Interface, which is "inherited"
// from by exactly 1 Tier-3 Interface.
Interface I%Domain% : IOrganism { /*...*/ }
// Implemented, and "Nebulous". See above on the Pattern section,
// as well as the comment on I%Domain%.
// Note: The %Kingdom% is indicative of a "stub"
// for any arbitrary pre-defined Kingdom interfaces.
// Consider to be a Tier-3 Interface, for which exactly 1 exists which
// implements each Tier-2 Interface.
interface I%Kingdom% : I%Domain%, IOrganism { /*...*/ }
Вся работа выполняется на интерфейсе IOrganism
, но известно, что каждый входной интерфейс для описанного метода (ниже): также I%Kingdom%
(который является также I%Domain%
).
Мне нужен метод в C #, который может получить входные данные IOrganism
, предположить, что это I%Kingdom%
, и преобразовать его в тип I%Domain%
с повышенным приведением в обобщенном виде, возвращая его как IOrganism
. Концептуально это похоже на распаковку, но с 3-уровневой системой и определяется через иерархические шаблоны между интерфейсами, без особого учета базовых типов объектов, только объявления интерфейсов.
// Given an IOrganism which is provided as a sub-typed
// I%Kingdom%instance , returns the input object as a
// Type-cast I%Domain%, and stored as an IOrganism.
public static IOrganism PromoteType(IOrganism organismAs%Kingdom%)
{
// Get the type of the base as the current base type.
// Is approximately typeof(I%Kingdom%), but
// Isn't actually a generic, and rather refers to
// An arbitrary instance of an I%Kingdom%-type
// of interface.
Type baseType = organismAs%Kingdom%.GetType();
// Throw exception if the type provided is not the expected type
// Note: type-checking is an abstraction,
// we need another logical statement to determine if it
// is the I%Kingdom% "generalized" interface type
// Assume the actual statement works.
if (baseType != typeof(I%Kingdom%))
{
// assume a more descriptive error string here.
string error = "Provided object was of an invalid type."
throw new InvalidArgumentException(string.Format(error));
}
// Stores the type of I%Domain%, inherantly.
// Use LinQ to retrieve the matching interited type.
// Note: The Name.Equals()-logic on "IDomain" is an abstraction
// of the real logic, we actually have another logical statement
// to determine if it is really the I%Domain%-pattern in
// a more "generalized" fashion. Assume the "real"
// variant of this statement works properly.
Type upcastTypeAsIDomain = baseType.GetInterfaces()
.FirstOrDefault(
currInterfaceType => currInterfaceType.Name.Equals("I%Domain%"));
// Note: For the third time, I%Domain% here is a logical abstraction -
// There is another statement I'm using which works,
// I'm just representing the effective statement
// Relative to the question's context.
if (upcastTypeAsIDomain != typeof(I%Domain%))
{
// A more meaningfull error message exists in reality.
string error = "Provided object didn't implement the proper I%Domain% interim type.";
throw new InvalidArgumentException(string.Format(error));
}
return /*This is the line I need help on*/;
}
У меня вопрос об этом операторе возврата, как мне выполнить «обобщенное» (не путать с обобщением C #) типизацию на предоставленном IOrganism
, известном как порядок интерфейса I%Kingdom%
, и верните его, как если бы это был I%Domain%
, концептуально похожий на Unboxing в C #, зная Type объекта в целом как IOrganism
, но затем приведя его к типу объявленного типа, и сохранив его, как будто это IOrganism
, но где GetType () вернет соответствующий I%Domain%
, а не истинный базовый I%Kingdom%
?
Отражение хорошо использовать здесь - я знаю о стоимости производительности, но это не будет проблемой в контексте, в котором он работает.
Я предполагаю некоторый мифический синтаксис, подобный:
// Obviously not a real Compileable line of C# - this is a pattern only.
IOrganism organismAsUpcastDomain = CAST_FROM_I%Kingdom%_TO_I%Domain%;
Существует ли какой-либо «универсальный» -каст (не путать с обобщениями C #), который преобразует из 1 типа (в качестве интерфейса) в другой тип (также в качестве интерфейса), делая вид, что базовый тип базового объекта теперь второй тип, если предположить, что иерархические определения верны? Таким образом, когда я сохраняю это organismAs%Kingdom%
в IOrganism
, organismAs%Kingdom%.GetType()
будет возвращать тип I%Domain%
вместо I%Kingdom%
, несмотря на то, что принципиально все еще остается I%Kindom%
внутри?
Контекст, в котором запускается эта программа, не будет «живым», в том смысле, что пользовательские запросы активно вынуждают логику выполняться, а, скорее, будут предварительно запускаться разработчиками, генерировать кеш-файл, который представляет собой результаты этой обработки, а затем могут быть просмотрены в режиме реального времени в соответствии с запросом, который будет забиваться от сотен тысяч до миллионов раз в день. Необходимо иметь возможность обрабатывать продвижение произвольного подтипа интерфейса (глубина 3) на 1 уровень вверх (глубина 2) (и храниться в типе интерфейса уровня 1).
Это может быть даже невозможно сделать в C #, так как я не уверен, насколько хорошо базовый .NET Framework различает базовый тип интерфейса, как если бы он был базовым типом базового объекта, и типом, в котором он хранится. поскольку, позволяя вам «притворяться», объект типа C
действительно является типом B
, хранящимся в типе A
, позволяя вам вызывать .GetType()
для экземпляра A, который будет возвращать тип, равный typeof(B)
, будучи действительно объектом типа C
, фактически заставляя его лгать о своем собственном наследии.
Поначалу это может выглядеть как ковариация и контравариантность, но отличается, потому что я работаю с произвольными типами интерфейсов, которые по поведению и иерархии похожи на I%Domain%
и I%Kingdom%
, и описываю их с использованием отражение.
Спасибо, что даже прочитали пост здесь, так как он
- Long
- запутанный
- Злоупотребляет термином "универсальный", когда на самом деле не ссылается на настоящие C # Generics
- Должен быть ненужным, но из-за среды, в которой я программирую (я пишу программу, которая должна использовать отражение для объявленных типов в общем порядке для выполнения работы со всеми входами независимо от типов, следуя определенным заранее известным шаблонам и иерархиям, в структуре данных, которая может буквально измениться в любое время для выполнения обобщенной работы над этой абстракцией).