Return 泛型方法中的特定类型取决于运行时没有反射或动态的枚举值
Return specific type in generic method depending on enum value without Reflection or dynamic during runtime
我有一个非通用的 IList
,我想在运行时根据 enum
值进行转换。
我无法在实现中更改非泛型 IList 的类型,因为它是库代码。
我也不想使用反射(因为它很慢)或动态关键字(因为它不安全并且可能导致错误)。
图书馆代码中有以下 class:
public class ListView //THIS IS LIBRARY CODE AND CAN NOT BE CHANGED
{
public IList itemsSource { get; set; }
}
然后在我继承自 ListView 的 CustomListView class 中,我想根据 ItemType 将 itemsSource 转换为适当的 class。
另一个限制是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");
}
}
}
但我希望它直接 return 正确的类型而不是使用动态。
类似于(下面的代码不起作用!):
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");
}
}
我将如何实施?
Edit/Appendage
正如你们所指出的,我应该澄清一些事情。
Class A 和 B 确实有相同的碱基 class。
但我希望能够不再从基本类型转换它(因为我已经在 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。它应该以某种方式隐式 return 正确的项目。
为了您的信息,我使用 Unity UI 工具包框架,但这与问题并不相关。
想想这个方法怎么用:
ItemType itemType = ...;
var x = listView.GetItems(itemType);
itemType
的值可能是A
,也可能是B
。那么 x
的类型应该是什么?它要么是 IList<A>
,要么是 IList<B>
,唯一的表达方式是使用 IList<A>
和 IList<B>
继承的类型,这让我们回到 IList
。如果您在编译时不知道您想要的类型,那么尝试将 return 类型更改为更具体的类型没有多大意义,因为您将无法访问它作为更具体的类型没有反映。
如果您知道您在编译时想要的类型,那么提供return所需类型的方法的重载:
public IList<A> GetAItems() { ... }
public IList<B> GetBItems() { ... }
编辑
如果您真的想要使用通用方法,您可以这样做:
public IList<T> GetItems<T>()
{
return itemsSource.Cast<T>().ToList();
}
但是我看不出为此创建一个方法有什么意义,而不是将该代码直接放在您需要特定类型的地方。
编辑 2
看过你的用例后,我真的会建议你使 CustomListView
class 通用。我知道你说图书馆会阻止这种情况,但有一些方法可以解决这个问题。您已经制作了一个 ItemType
枚举,您可以为每个项目类型制作一个 CustomListView<T>
的子 class:
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
}
}
您希望如何使用这种方法?类型参数由方法的调用者设置。无法使用该方法设置类型参数。请具体说明用法。
你可以试试这些:
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 在评论中所建议的那样:
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");
}
}
我有一个非通用的 IList
,我想在运行时根据 enum
值进行转换。
我无法在实现中更改非泛型 IList 的类型,因为它是库代码。
我也不想使用反射(因为它很慢)或动态关键字(因为它不安全并且可能导致错误)。
图书馆代码中有以下 class:
public class ListView //THIS IS LIBRARY CODE AND CAN NOT BE CHANGED
{
public IList itemsSource { get; set; }
}
然后在我继承自 ListView 的 CustomListView class 中,我想根据 ItemType 将 itemsSource 转换为适当的 class。
另一个限制是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");
}
}
}
但我希望它直接 return 正确的类型而不是使用动态。
类似于(下面的代码不起作用!):
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");
}
}
我将如何实施?
Edit/Appendage
正如你们所指出的,我应该澄清一些事情。
Class A 和 B 确实有相同的碱基 class。 但我希望能够不再从基本类型转换它(因为我已经在 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。它应该以某种方式隐式 return 正确的项目。
为了您的信息,我使用 Unity UI 工具包框架,但这与问题并不相关。
想想这个方法怎么用:
ItemType itemType = ...;
var x = listView.GetItems(itemType);
itemType
的值可能是A
,也可能是B
。那么 x
的类型应该是什么?它要么是 IList<A>
,要么是 IList<B>
,唯一的表达方式是使用 IList<A>
和 IList<B>
继承的类型,这让我们回到 IList
。如果您在编译时不知道您想要的类型,那么尝试将 return 类型更改为更具体的类型没有多大意义,因为您将无法访问它作为更具体的类型没有反映。
如果您知道您在编译时想要的类型,那么提供return所需类型的方法的重载:
public IList<A> GetAItems() { ... }
public IList<B> GetBItems() { ... }
编辑
如果您真的想要使用通用方法,您可以这样做:
public IList<T> GetItems<T>()
{
return itemsSource.Cast<T>().ToList();
}
但是我看不出为此创建一个方法有什么意义,而不是将该代码直接放在您需要特定类型的地方。
编辑 2
看过你的用例后,我真的会建议你使 CustomListView
class 通用。我知道你说图书馆会阻止这种情况,但有一些方法可以解决这个问题。您已经制作了一个 ItemType
枚举,您可以为每个项目类型制作一个 CustomListView<T>
的子 class:
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
}
}
您希望如何使用这种方法?类型参数由方法的调用者设置。无法使用该方法设置类型参数。请具体说明用法。
你可以试试这些:
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 在评论中所建议的那样:
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");
}
}