Return 具有动态选择类型的列表<type>,同时也转换为该类型 (C#)

Return a List<type> with a dynamically selected type while also casting to that type (C#)

已解决,解决办法见post文末。


我有一个 return 附件列表的方法。我有三种类型的附件,它们都扩展了一个名为 GenericAttachment:

的 class
GenericAttachment
||
==> FormA_Attachment
==> FormB_Attachment
==> FormC_Attachment

我也有不同的表单类型,它们都扩展了一个名为 GenericForm:

的 class
GenericForm
||
==> FormA
==> FormB
==> FormC

该方法必须采用 Type 参数(FormA、FormB 或 FormC)和 return 适当类型的附件。

我先试过这个:

public static List<GenericAttachment> GetAllAttachmentsByFormID<T>(int sqlFormId, Type type) where T : GenericForm
{
        //this returns e.g. FormA_Attachment based on FormA as the input
        Type attachmentType = GetAttachmentTypeByFormType(type);

        //Call a generic function (overload of this one) 
        //that returns all attachments and requires a specific type argument.
        //Meanwhile, .Invoke()'s return type is just an `object`
        var attachments = typeof(AttachmentManager)
                              .GetMethod("GetAllAttachmentsByFormID", new[] { typeof(int) }) // select the correct overload for the method
                              .MakeGenericMethod(attachmentType)
                              .Invoke(new AttachmentManager(), new object[] { sqlFormId });

        return (List<GenericAttachment>)attachments;
}

但是,转换在运行时失败 ("failed to cast")。

然后我用 if/else 语句尝试了一种更笨的方法,但它没有编译,因为 "Cannot convert List<FormA_Attachment> to List<GenericAttachment>"。尝试使用 Convert.ChangeType 和普通演员表,如下所示。

奇怪的是它没有编译,因为例如FormA_Attachment 扩展 GenericAttachment.

        if (attachmentType == typeof(FormA_Attachment))
        {
            return (List<FormA_Attachment>) Convert.ChangeType(attachments, typeof(List<FormA_Attachment>));
        }
        else if (attachmentType == typeof(FormB_Attachment))
        {
            return (List<FormB_Attachment>)attachments;
        }
        else if (attachmentType == typeof(FormC_Attachment))
        {
            return (List<FormC_Attachment>)attachments;
        }
        else
        {
            throw new Exception("Invalid attachment class type.");
        }

如何将 attachments 转换为动态选择 typeList<type>


解决方案:

感谢@Mikhail Neofitov,以下代码有效。

attachments 的类型是 object 因为这是 .Invoke() return 的类型。

所以我首先将其转换为特定类型,然后使用 .OfType<GenericAttachment>().ToList().

转换为不太特定的类型
        if (attachmentType == typeof(FormA_Attachment))
        {
            return ((List<FormA_Attachment>) Convert.ChangeType(attachments, typeof(List<FormA_Attachment>))).OfType<GenericAttachment>().ToList();
        }
        else if (attachmentType == typeof(FormB_Attachment))
        ... 
        //similar code

C# 不允许 types covariance,这意味着 List<string> 不能简单地转换为 List<object>

在您的情况下,您可以使用 LINQ 扩展方法 OfType(),如下所示:

return attachments.OfType<GenericAttachment>().ToList();

请注意,我想,您可以修改您的应用架构以将 GenericArgument 的结果类型传递给 GenericForm 的通用参数,并定义一个抽象方法以在结果中返回结果附件类型。另外,你的通用参数 <T> 没用,你不要在方法体中使用它。

看看this。这是内存高效转换 List<Derived>List<Base>

的示例

您可以在此处使用 协方差List<T> 不是变体,但它实现了 IEnumerable<out T>,它在 T 中是协变的。这意味着您不能将 object 转换为 List<GenericAttachment>,但可以将其转换为IEnumerable<GenericAttachment>。因此,您应该能够执行以下操作,而不是所有这些 ifs:

return ((IEnumerable<GenericAttachment>)attachments).ToList();