返回带有动态选择类型的List <type>,同时也转换为该类型(C#)

时间:2017-03-09 06:16:29

标签: c# casting system.reflection

已解决,请参阅帖子末尾的解决方案。

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

GenericAttachment
||
==> FormA_Attachment
==> FormB_Attachment
==> FormC_Attachment

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

GenericForm
||
==> FormA
==> FormB
==> FormC

该方法必须采用FormA,FormB或FormC的Type参数,并返回相应类型的附件。

我先试过这个:

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;
}

然而,演员阵容在运行时失败(&#34;未能演员&#34;)。

然后我用if / else语句尝试了一种笨拙的方式,但它没有编译,因为&#34;无法将List<FormA_Attachment>转换为List<GenericAttachment>&#34;。尝试使用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转换为动态选择List<type>的{​​{1}}?

解决方案

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

type的类型为attachments,因为这是object返回的内容。

所以我首先将其转换为特定类型,然后使用.Invoke()转换为不太具体的类型。

.OfType<GenericAttachment>().ToList()

3 个答案:

答案 0 :(得分:4)

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

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

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

我想,您可以修改应用程序体系结构,将结果类型的GenericArgument传递给GenericForm的泛型参数,并定义一个抽象方法,用于在结果类型中返回结果附件。此外,您的通用参数<T>没用,您不在方法体中使用它。

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

看看this。这是将List<Derived>投射到List<Base>

的内存效率高的示例