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>();