在泛型方法中返回特定类型,具体取决于运行时没有反射或动态的枚举值
Posted
技术标签:
【中文标题】在泛型方法中返回特定类型,具体取决于运行时没有反射或动态的枚举值【英文标题】:Return specific type in generic method depending on enum value without Reflection or dynamic during runtime 【发布时间】:2021-12-28 17:17:18 【问题描述】:我有一个非泛型 IList
,我想在运行时根据 enum
值进行转换。
我无法在实现中更改非泛型 IList 的类型,因为它是库代码。
我也不想使用反射(因为它很慢)或动态关键字(因为它不安全并且可能导致错误)。
在图书馆代码中有以下类:
public class ListView //THIS IS LIBRARY CODE AND CAN NOT BE CHANGED
public IList itemsSource get; set;
然后在继承自 ListView 的 CustomListView 类中,我想根据 ItemType 将 itemsSource 转换为适当的类。
另一个限制是 CustomListView 不能是通用的(由我们使用的库决定)
public class CustomListView : ListView
public dynamic GetItems()
switch (ItemType)
case ItemType.A:
return itemsSource.Cast<A>().ToList();
case ItemType.B:
return itemsSource.Cast<B>().ToList();
default:
throw new InvalidOperationException("Not supported");
但我希望它直接返回正确的类型,而不是使用动态。
类似的东西(下面的代码不起作用!):
public IList<T> GetItems(ItemType itemType) //The type of T should change depending on what i return
switch (ItemType)
case ItemType.A:
return itemsSource.Cast<A>().ToList();
case ItemType.B:
return itemsSource.Cast<B>().ToList();
default:
throw new InvalidOperationException("Not supported");
我将如何实现它?
编辑/附加
正如你们指出的,我应该澄清一些事情。
A 类和 B 类确实具有相同的基类。 但是我希望能够不再从基本类型中转换它(因为我已经在 GetItems() 方法中转换它并且 ItemType 的值也是已知的)。
我希望能够做到以下几点
IList<A> aItems = listView.GetItems()
没有强制转换。
所有这一切背后的想法是拥有一个可以处理多种项目类型的通用 CustomListView。这些项目将被添加到 itemSource。这些项目的类型由 ItemType 确定。
我就是这样用的
public class UiForClassA
public void Foo()
CustomListView customListView = new CustomListView(ItemType.A);
IList<A> itemsOfCustomListView = customListView.GetItems(); //No cast needed because it should somehow implicitly know that.
我不想在使用 CustomListView 的任何地方都使用 Casts。它应该以某种方式隐式返回正确的项目。
为了您的信息,我使用 Unity UI Toolkit Framework,但这与问题并不真正相关。
【问题讨论】:
如果类“A”和“B”没有通用功能,那么您应该返回“IList 你不能这样做。指定类型参数的是调用者。您必须声明public IList<T> GetItems<T>()
并使用 var list = GetItems<A>();
调用它。如果GetItems
返回不同类型的列表,你想如何消费它们?消费者也需要是通用的。
【参考方案1】:
想一想如何使用这种方法:
ItemType itemType = ...;
var x = listView.GetItems(itemType);
itemType
的值可以是A
,也可以是B
。那么x
的类型应该是什么?它要么是IList<A>
,要么是IList<B>
,唯一的表达方式是使用IList<A>
和IList<B>
都继承自的类型,这会将我们带回到IList
。如果您在编译时不知道您想要的类型,那么尝试将返回类型更改为更具体的类型没有多大意义,因为您将无法在没有反射的情况下将其作为更具体的类型访问。
如果您确实在编译时知道所需的类型,则提供返回所需类型的方法的重载:
public IList<A> GetAItems() ...
public IList<B> GetBItems() ...
编辑
如果你真的想要使用泛型方法,你可以这样做:
public IList<T> GetItems<T>()
return itemsSource.Cast<T>().ToList();
但是我看不出为此创建方法的意义,而不是将代码直接放在需要特定类型的地方。
编辑 2
看过您的用例后,我真的建议您将 CustomListView
类设为通用。我知道您说图书馆会阻止这种情况,但是有一些方法可以解决这个问题。你已经创建了一个ItemType
枚举,你可以为每个项目类型创建一个CustomListView<T>
的子类:
public class CustomListView<T> : ListView
public IList<T> GetItems() => itemsSources.Cast<T>().ToList();
public class CustomListViewOfA : CustomListView<A>
public class CustomListViewOfB : CustomListView<B>
public class UiForClassA
public void Foo()
var customListView = new CustomListViewOfA();
var itemsOfCustomListView = customListView.GetItems(); //No cast needed
【讨论】:
只是我明确设置了一个 ItemType 但仍然必须在特定代码中手动转换它。所以我想要一个根据 ItemType 隐式返回正确类型的方法。我不想在此 ListView 的每次使用中都添加 Cast 语句,我想要一种通用方法来处理它。 我还是不明白你为什么需要一个ItemType
变量。如果您向我们展示您要如何处理这些物品,将会有所帮助。看起来您正在使用 UI 库/框架 - 如果您提供有关包含 ListView 的类的一些详细信息,并尝试访问特定类型的项目,人们可能能够提供更好的建议【参考方案2】:
您希望如何使用这种方法?类型参数由方法的调用者设置。无法从方法中设置类型参数。请说明用途。
你可以试试这些:
IList<T> GetItems<T>(ItemType itemType)
switch (itemType)
case ItemType.A:
return (IList<T>)(IList)(itemsSource.Cast<A>().ToList());
case ItemType.B:
return (IList<T>)(IList)(itemsSource.Cast<B>().ToList());
default:
throw new InvalidOperationException("Not supported");
IList GetItems(ItemType itemType)
switch (itemType)
case ItemType.A:
return itemsSource.Cast<A>().ToList();
case ItemType.B:
return itemsSource.Cast<B>().ToList();
default:
throw new InvalidOperationException("Not supported");
或者,正如 @Qwertyluk 在 cmets 中所建议的那样:
private IList<object> GetItems(ItemType itemType)
switch (itemType)
case ItemType.A:
case ItemType.B:
return itemsSource.Cast<object>().ToList();
default:
throw new InvalidOperationException("Not supported");
【讨论】:
以上是关于在泛型方法中返回特定类型,具体取决于运行时没有反射或动态的枚举值的主要内容,如果未能解决你的问题,请参考以下文章