将 SDKList 转换为 List<T>

huangapple go评论74阅读模式
英文:

Convert SDKList to List<T>

问题

我有一个来自SDK的类,它充当一个列表。它的名字是*SDKList*。
*SDKList*有一个成员Item,其中包含几种特定于SDK的类型(例如*SDKElement,SDKSurface,SDKBody*)。
还有一个成员Type,它指定了Item是*SDKElement,SDKSurface还是SDKBody*。

我想要的是一个通用的方法,将*SDKList*转换为C#的List&lt;T&gt;。

到目前为止,我有一个非通用的方法,针对Item类型SDKElement:
```csharp
public static List&lt;SDKElement&gt; sdkListToCSharpList(SDKList sdkList)
{
    if (sdkList.ItemType != (short)VListTypes.LTYPE_ELEM) return null;
    List&lt;SDKElement&gt; result = new List&lt;SDKElement&gt;();
    for (int i = 1; i &lt;= sdkList.Count; i++)
    {
        SDKElement elm = sdkList.Item(i);
        result.Add(elm);
    }
    return result;
}

我想要的是像这样的方法:

public static List&lt;T&gt; sdkListToCSharpList(SDKList sdkList)
{
...
}

方法需要如何更改以使其通用并处理所有种类的Item类型?
因为我没有太多使用泛型的经验,所以我不知道如何使它通用,因为SDKList是一个单一的类型,它包含实际的通用项。

提前感谢您。


<details>
<summary>英文:</summary>

I do have a class from a SDK which acts as an list. Its name is *SDKList*.
*SDKList* has a member Item, which contains several SDK specific Types (e.g. *SDKElement, SDKSurface, SDKBody*)
There is also a member Type which specifies wheather the Items are *SDKElement, SDKSurface or SDKBody*.

What i want is a generic method to convert the *SDKList* in a C# List&lt;T&gt;.

Sofar I have a non generic method for the Item type SDKElement:

public static List<SDKElement> sdkListToCSharpList(SDKList sdkList)
{
if (sdkList.ItemType != (short)VListTypes.LTYPE_ELEM) return null;
List<SDKElement> result = new List<SDKElement>();
for (int i = 1; i <= sdkList.Count; i++)
{
SDKElement elm = sdkList.Item(i);
result.Add(elm);
}
return result;
}

What I want is something like this:

public static List<T> sdkListToCSharpList(SDKList sdkList)
{
...
}


How does the method need to be changed to work generic and process all kinds of Item Types?
Since i haven&#39;t worked worked much with gneric I don&#39;t understand how to make it generic since *SDKList* is a single Type and contains the acutual generic Items.
 
Thank you in advance.

</details>


# 答案1
**得分**: 2

public static List<T> sdkListToCSharpList<T>(SDKList sdkList)

根据您的描述,列表中对象的类型可能在运行时变化。泛型是一个编译时的概念,所以你不能在运行时使泛型类型变化,至少不使用反射的情况下。

您可以声明您希望列表具有的类型,如下所示:

public static List<T> sdkListToCSharpList<T>(SDKList sdkList)

但是,您需要找到一种处理运行时类型与编译时泛型类型不匹配的情况的方式。这可以是返回一个空列表、引发异常或使用其他方式来表示错误。

我个人会使用LINQ来为列表创建一个迭代器:

public static IEnumerable<T> ToEnumerable<T>(this SDKList sdkList){
    var runtimeType = sdkList.ItemType switch{
           VListTypes.LTYPE_ELEM => typeof(SDKElement)
           VListTypes.LTYPE_SURF => typeof(SDKSurface )
           ...
           _ => throw new InvalidOperationException(...)
    };
    if(runtimeType != typeof(T)){
         throw new InvalidOperationException(...);
    }
    for (int i = 1; i <= sdkList.Count; i++){ // one based indexing? really?
        yield return (T)sdkList.Item(i);
    }
}

然后像这样调用它:

var sdkElementList = mySdkList.ToEnumerable<SDKElement>().ToList();

这样,如果实际运行时类型与您在运行时期望的类型不匹配,将引发运行时异常。如果您希望得到一个空列表,您可以删除所有类型检查,返回一个IEnumerable<object>,并使用.OfType<T>()来仅获取运行时类型与预期类型匹配的对象。

<details>
<summary>英文:</summary>

&gt; What I want is something like this:
&gt; `public static List&lt;T&gt; sdkListToCSharpList(SDKList sdkList)`

You cannot. According to your description the type of the objects in the list may vary in runtime. Generics is a compile time concept, so you cannot make a generic type vary at runtime, at least not without reflection.

What you can do is declare the type you expect the list to have, i.e. 

    public static List&lt;T&gt; sdkListToCSharpList&lt;T&gt;(SDKList sdkList)

But you will need some way to handle cases where the runtime type does not match your compile time, generic, type. This might be to return an empty list, throw an exception, or some other way to signal the error.

I would personally use LINQ to create an iterator for the list:

public static IEnumerable<T> ToEnumerable<T>(this SDKList sdkList){
var runtimeType = sdkList.ItemType switch{
VListTypes.LTYPE_ELEM => typeof(SDKElement)
VListTypes.LTYPE_SURF => typeof(SDKSurface )
...
_ => throw new InvalidOperationException(...)
};
if(runtimeType != typeof(T)){
throw new InvalidOperationException(...);
}
for (int i = 1; i <= sdkList.Count; i++){ // one based indexing? really?
yield return (T)sdkList.Item(i);
}
}

And call it like:

var sdkElementList = mySdkList.ToEnumerable<SDKElement>().ToList();


That way you will get a runtime exception if your actual runtime type does not match the type you expect in runtime. If you instead want an empty list you could remove all the type-checks, return a `IEnumerable&lt;object&gt;` and use `.OfType&lt;T&gt;()` to only get the objects where the runtime type matches the expected type. 

</details>



huangapple
  • 本文由 发表于 2023年3月1日 16:08:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/75600981.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定