I have a class that operates on objects that come from external API, and extracts information from them with different procedures based on their type (in the following example, these types are Body2
, Face2
). I am using overloaded functions for this:
我有一个类,它对来自外部API的对象进行操作,并根据它们的类型(在下面的示例中,这些类型是Body2,Face2)使用不同的过程从它们中提取信息。我使用重载函数来实现:
static class InfoExtractor
{
public static InfoProperty Extract(Body2 body)
{
//...
}
public static InfoProperty Extract(Face2 face)
{
//...
}
}
Due to the nature of that API, it is impossible to extract the type of these objects (at this point are all of type object
), so their type is saved in a wrapper:
由于该API的性质,不可能提取这些对象的类型(此时它们都是对象类型),因此它们的类型保存在包装器中:
class Body2Wrapper : ApiObjectWrapper
{
object objectRef;
Type objectType = typeof(Body2)
}
(ApiObjectWrapper
is an interface that allows me to put different implementations of it in a single list)
(ApiObjectWrapper是一个接口,它允许我将它的不同实现放在一个列表中)
Finally, I have a list of ApiObjectWrapper
, and as I iterate through it, I want to call InfoExtractor.Extract()
with the correct overload based on the ApiObjectWrapper.objectType
. So ideally it would be something like this:
最后,我有一个ApiObjectWrapper列表,当我遍历它时,我想调用InfoExtractor.Extract(),并根据ApiObjectWrapper.objectType使用正确的重载。所以理想的情况应该是这样的:
foreach (ApiObjectWrapper apiObject in apiObjects)
{
InfoProperty info = InfoExtractor.Extract((apiObject.objectType)apiObject.objectRef);
//...
}
The idea here is that I would cast the apiObject.objectRef
to whatever type was saved in apiObject.objectType
, so that the correct overload function of InfoExtractor.Extract
would be called. But it doesn't seem to work like this.
这里的想法是,我将apiObject.objectRef转换为保存在apiObt.objectType中的任何类型,这样就可以调用InfoExtractor.Extract的正确重载函数。但它似乎不是这样运作的。
What is the correct way to cast that object into the type that I saved in a variable?
将该对象转换为我保存在变量中的类型的正确方法是什么?
EDIT: I know that normally one would use polymorphism for this, but I can't because I can't change these underlying types, and I would really like to avoid saving the types of these objects in a string, and then having a switch
to check these types and write explicit casts, like this:
编辑:我知道通常情况下会使用多态,但我不能,因为我不能更改这些底层类型,我真的希望避免将这些对象的类型保存在字符串中,然后让开关检查这些类型并编写显式强制转换,如下所示:
switch (apiObject.objectType)
{
case "Body2":
InfoProperty info = InfoExtractor.Extract((Body2)apiObject.objectRef)
break;
case "Face2":
InfoProperty info = InfoExtractor.Extract((Face2)apiObject.objectRef)
break;
}
更多回答
A cast requires that you know the type at compile time. Type
is when you only know the type at runtime. These are incompatible. You're probably going to have to write some wrapper types (possibly using code generation if there's a lot of them).
强制转换要求您在编译时知道类型。类型是只有在运行时才知道类型的情况。这些是不相容的。您可能必须编写一些包装器类型(如果有很多包装器类型,则可能使用代码生成)。
优秀答案推荐
While you could easily use reflection to solve this, that is probably inefficient.
虽然您可以很容易地使用反射来解决这个问题,但这可能效率很低。
One option is to keep a list of possible overloads as Func<ApiObjectWrapper, InfoProperty>
delegates in a Dictionary. Each delegate itself knows how to cast to the right type and call the correct fuction, you just need to get the delegate out of the dictionary.
一种选择是在字典中保留一个可能的重载列表,作为Func
委托。每个委托本身都知道如何强制转换为正确的类型并调用正确的函数,您只需从字典中取出委托即可。
static class InfoExtractor
{
static Dictionary<Type, Func<ApiObjectWrapper, InfoProperty>> ExtractFuncs = new {
{ typeof(Body2), apiObject => Extract((Body2)apiObject.objectRef) },
{ typeof(Face2), apiObject => Extract((Face2)apiObject.objectRef) },
};
public static InfoProperty ExtractFromWrapper(ApiObjectWrapper apiObject)
{
if(!ExtractFuncs.TryGetValue(apiObject.objectType, out var func))
throw new ArgumentException("Invalid Object Type");
return func(apiObject);
}
public static InfoProperty Extract(Body2 body)
{
//...
}
public static InfoProperty Extract(Face2 face)
{
//...
}
}
Then you can simply do
然后你可以简单地做
foreach (var apiObject in apiObjects)
{
var info = InfoExtractor.ExtractFromWrapper(apiObject);
//...
}
You cannot cast - that would require the object to be of that type. If they are object, then a cast will not work. Cast works if you have a typed obejct and STORE it in an object variable - and then take it out. But the object must be the correct type.
您不能强制转换--这将要求对象属于该类型。如果它们是对象,那么强制转换将不起作用。如果您有一个类型化的bejct,并将其存储在对象变量中,然后将其取出,则CAST起作用。但对象必须是正确的类型。
You can transform, in a method (possibly using automapper), into a type you return.
您可以在方法中(可能使用自动映射程序)将其转换为您返回的类型。
This is a general problem with many API - especially external, especially JSON based, where the type is depending on some parameters that the serializer can not easily pick up. What I generally do in this case is to deserialize into one object with all properties, then after analysis go down into a more specific object that is returned from my API wrapper.
这是许多API普遍存在的问题--尤其是外部API,尤其是基于JSON的API,其类型依赖于序列化程序不容易获取的一些参数。在这种情况下,我通常做的是反序列化为一个具有所有属性的对象,然后在分析之后进入从我的API包装器返回的更具体的对象。
更多回答
我是一名优秀的程序员,十分优秀!