InvalidCastException:无法将泛型列表转换为对象

InvalidCastException: Unable cast generic List to object

有人可以向我解释为什么以下转换不起作用以及问题的解决方案。

我有一个 GroupedResult:

public class GroupedResult<TKey, TElement>
{
    public TKey Key { get; set; }

    private readonly IEnumerable<TElement> source;

    public GroupedResult(TKey key, IEnumerable<TElement> source)
    {
        this.source = source;
        this.Key = key;
    }
}

public class Bacon 
{
}

我想将 List<string, Bacon> 转换为 List<string, object>。我尝试了以下和其他方法。

var list = new List<GroupedResult<string, Bacon>>
    {
        new GroupedResult<string, Bacon>("1", new List<Bacon>()),
        new GroupedResult<string, Bacon>("2", new List<Bacon>())
    };

var result = list.Cast<GroupedResult<string, object>>().ToList();

但我总是得到以下错误:

InvalidCastException: Unable to cast object of type 'GroupedResult2[System.String,UserQuery+Bacon]' to type 'GroupedResult2[System.String,System.Object]'.

最好从 GroupedResult 开始然后你可以这样做

new GroupedResult<string, object>("2", new List<Bacon>())

为什么不使用 GroupedResult<string, object> 而不是 GroupedResult<string, Bacon>?像这样:

var list = new List<GroupedResult<string, object>>
    {
        new GroupedResult<string, object>("1", new List<Bacon>()),
        new GroupedResult<string, object>("2", new List<Bacon>())
    };

要实现这一点,您必须使用接口而不是 class 类型。

public interface IGroupResult<TKey, out TElement>
{
    TKey Key { get; set; }
}

public class GroupedResult<TKey, TElement> : IGroupResult<TKey, TElement>
{
    public TKey Key { get; set; }

    private readonly IEnumerable<TElement> source;

    public GroupedResult(TKey key, IEnumerable<TElement> source)
    {
        this.source = source;
        this.Key = key;
    }
}

public class Bacon
{

}

然后你可以这样做

IGroupResult<string, Bacon> g = new GroupedResult<string, Bacon>("1", new List<Bacon>());

var result = (IGroupResult<string, object>)g;

那是因为协变只允许在接口和委托上使用,而不是 classes。请注意,如果类型仅来自接口(方法 return 类型和只读属性),则只应将其标记为协变。

虽然您应该问问自己为什么在使用泛型时要将某些内容强制转换为 object。泛型的要点是避免必须使用 object 类型作为包罗万象,这可能表明您的设计存在缺陷,您可能需要重新考虑。

您可以在 GroupedResult class 中使用 Cast 方法并使用它来进行转换!

public class GroupedResult<TKey, TElement>
{
    public TKey Key { get; set; }

    private readonly IEnumerable<TElement> source;

    public GroupedResult(TKey key, IEnumerable<TElement> source)
    {
        this.source = source;
        this.Key = key;
    }

    public GroupedResult<TKey, object> Cast()
    {
        return new GroupedResult<TKey, object>(Key, source.Cast<object>());
    }
}

public class Bacon
{ 
}

static void Main(string[] args)
{

   var list = new List<GroupedResult<string, Bacon>>
   {
        new GroupedResult<string, Bacon>("1", new List<Bacon>()),
        new GroupedResult<string, Bacon>("2", new List<Bacon>())
    };

    // var result = list.Cast<GroupedResult<string, object>>().ToList();
    List<GroupedResult<string,object>> result = list.Select(B => B.Cast()).ToList();
}