C# 如何铸造IEnumerable<;对象>;到IEnumerable<;运行时类型>;
我正在努力实现以下目标 假设我有这个数据模型:C# 如何铸造IEnumerable<;对象>;到IEnumerable<;运行时类型>;,c#,.net,linq,generics,casting,C#,.net,Linq,Generics,Casting,我正在努力实现以下目标 假设我有这个数据模型: public class Article { public ICollection<string> Tags { get; set; } } 但这将给我留下一个运行时类型,我不能将其用作Cast() 如何将IEnumerable转换为动态类型的IEnumerable 我应该注意,在我的模型上不允许使用复杂类型,所以类似于: public ICollection<Tag> Tags { get; set; } 公
public class Article
{
public ICollection<string> Tags { get; set; }
}
但这将给我留下一个运行时类型
,我不能将其用作Cast()
如何将IEnumerable
转换为动态类型的IEnumerable
我应该注意,在我的模型上不允许使用复杂类型,所以类似于:
public ICollection<Tag> Tags { get; set; }
公共ICollection标记{get;set;}
不会发生。我只处理基本类型。我相信System.Convert具备您所需的功能:
Type genericArg = collectionType.GetGenericArguments().First();
foreach(var obj in collection) {
yield return Convert.ChangeType(obj, genericArg);
}
Enumerable.Cast(此IEnumerable源代码)
通常是您需要的。如果需要不同的变体,可以使用反射自己关闭泛型类型:
class Program
{
static void Main(string[] args)
{
var source = new List<object> {
"foo",
"bar",
"baz"
};
var type = typeof(string); // or however you find out the type
var castMethod = typeof(Enumerable)
.GetMethod("Cast").MakeGenericMethod(
new[] {
type
});
var result = (IEnumerable<string>)
castMethod.Invoke(null, new object[] {source});
foreach (var str in result)
{
Console.WriteLine(str.ToUpper());
}
}
}
类程序
{
静态void Main(字符串[]参数)
{
var source=新列表{
“福”,
“酒吧”,
“巴兹”
};
var type=typeof(string);//或者您如何找到类型
var castMethod=typeof(可枚举)
.GetMethod(“Cast”).MakeGenericMethod(
新[]{
类型
});
变量结果=(IEnumerable)
Invoke(null,新对象[]{source});
foreach(结果中的var str)
{
Console.WriteLine(str.ToUpper());
}
}
}
另一个问题是,从一个列表转换到另一个列表没有意义-泛型参数是不变的,因为集合是读写的。(由于历史原因,数组允许一些这样的强制转换。)但是,如果您只是在阅读,那么从Cast
返回的IEnumerable
就足够了。您对强制转换有一个基本的误解
强制转换操作的结果类型必须在编译时已知。
考虑以下示例:
string a = "abc";
object b = (object)a;
string c = (string)b;
a
、b
和c
的运行时类型相同。它是字符串
。编译时类型不同。强制转换仅与编译时类型相关
因此,你的问题的答案是
如何将IEnumerable
强制转换为IEnumerable
是:你没有。强制转换对于运行时类型没有意义
也就是说,让我为您真正的问题提供一个解决方案:假设您有一个IEnumerable values
,一个类型myTargetType
,并且希望创建一个包含这些值的列表
首先,使用反射创建列表:
var listType = typeof(List<>).MakeGenericType(myTargetType);
IList myList = (IList)Activator.CreateInstance(listType);
显然,如果值的条目不是运行时类型myTargetType
,则Add
将执行此操作
“”“结果类型可以是泛型类型,但。您需要实现一个泛型方法,该方法从数据库api获取结果,并根据您的模型返回适当的集合,如下所示:
private ICollection<T> RetrieveTags()
{
// Get tags using database api
return tags.Cast<T>();
}
private ICollection RetrieveTags()
{
//使用数据库api获取标记
return-tags.Cast();
}
然后根据需要调用此方法以获取模型,例如:
ICollection<int> t1 = RetrieveTags<int>();
ICollection<string> t2 = RetrieveTags<string>();
ICollection t1=RetrieveTags();
i集合t2=检索标记();
我不明白Cast()在每种情况下都有什么问题。如果您不知道这些值是什么类型的,您将如何使用它们?“我的数据库的API将它们作为列表返回给我
”似乎修复API可以解决您的问题。为什么它不能返回不同的集合类型?我不能使用任何泛型方法,因为直到运行时我才知道t
。这个映射方法将被许多模型调用,有时我必须转换为IEnumerable
,有时转换为IEnumerable
,如果您在运行时之前不知道它是什么类型,为什么获取一个类型的IEnumerable
会对您有所帮助?你到底想做什么?问题是我不知道t
的类型,直到runtime@MatiCicero如果需要,您可以在运行时使用反射关闭它。@MatiCicero我添加了一个在运行时关闭泛型的示例。如果您假设他的DB层处理得到正确的类型,那么是的。此解决方案允许他指定目标集合类型,并且只要存在转换规则,它就可以工作。“强制转换操作的结果类型必须在编译时已知”-不正确-您可以强制转换为泛型类型-这就是Linq的强制转换的工作方式。@DStanley:true,但泛型类型也必须在编译时已知:只有在为其提供具体类型或其他泛型类型时才能调用Cast
。(在后一种情况下,可以对该类型使用相同的参数。在调用链的末尾必须有一个具体的类型。)不能使用运行时类型调用它。我将在问题中澄清这一点,以避免误解。
private ICollection<T> RetrieveTags()
{
// Get tags using database api
return tags.Cast<T>();
}
ICollection<int> t1 = RetrieveTags<int>();
ICollection<string> t2 = RetrieveTags<string>();