【发布时间】:2019-09-04 00:36:22
【问题描述】:
这里有一个奇怪的问题 - 由于我工作的环境而出现的一些问题。
前言:
我将滥用分类学等级中众所周知的抽象来描述我遇到的情况 - 通过设计决策,这些决策不是我自己的,现在已经在高使用率数据处理系统上投入生产。 我正在使用(使用)其他人在工作中设计的 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% 类型,并将其返回为 @987654334 @。这在概念上类似于拆箱,但具有 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*/;
}
我的问题是关于那个 return 语句,我如何在提供的IOrganism 上执行“通用”(不要与 C# 泛型混淆)类型转换,已知是接口的I%Kingdom% 顺序,以及返回它,就好像它是一个I%Domain%,在概念上类似于C#的拆箱,将对象的类型牢牢地知道为IOrganism,然后将其转换为声明类型的类型,并将其存储为好像它是@987654340 @,但是 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)提升到上一层(深度 2)(并存储在第 1 层接口类型中)。
在 C# 中甚至不可能做到这一点,因为我不确定底层 .NET 框架如何区分基本接口类型(就好像它是底层对象的基类型一样)和它正在存储的类型因为,允许您“假装”类型为C 的对象实际上是类型B,存储在类型A 中,允许您在A 的实例上调用.GetType(),这将返回一个等于@ 的类型987654354@,虽然确实是 C 类型的对象,但实际上使它对自己的遗产撒谎。
这可能看起来类似于协方差和逆变,但不同的是,因为我正在使用在行为和层次上类似于I%Domain% 和I%Kingdom% 的任意接口类型,同时使用描述它们反射。
感谢您阅读这里的帖子,因为它是
- 长
- 错综复杂
- 在实际上并非指真正的 C# 泛型时滥用术语“泛型”
- 应该是不必要的,但由于我正在编程的环境,(我正在编写一个程序,它需要以一般方式对声明的类型使用反射来执行所有输入,而不管类型,遵循某些预先知道的模式和层次结构,在一个可以随时改变的数据结构上,以执行这个抽象的通用工作)。
【问题讨论】:
-
如果你使用类型参数语法有点难以阅读,但实际上只是接口名称中的占位符
-
我同意。您对语法替换有什么想法吗?
-
我想我可以使用 I%Domain%、I%Kingdom% 等类似的符号,并在我的前提下将该符号描述为约定。
-
另外,我理解正确吗?是否要更改实例的type?比如,
GetType()返回的类型与原来不同? -
我不想改变底层类型,我想让对象谎报类型并假装它实际上是向上转换的变体的类型。我正在使用的系统实际上已经在执行此操作 - 我正在使用一个具体对象,调用 .GetType() 返回 I
的类型而不是具体类型,并且我正在寻找操作该对象强制它返回 I 而不是 I ,以用于对向上转换的变体进行反思。这就是为什么这个请求对我来说如此奇怪的部分原因,让我质疑这种方法在 C# 中的可行性。
标签: c# interface system.reflection upcasting type-promotion