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
转换为动态选择 type
的 List<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>
。因此,您应该能够执行以下操作,而不是所有这些 if
s:
return ((IEnumerable<GenericAttachment>)attachments).ToList();
已解决,解决办法见post文末。
我有一个 return 附件列表的方法。我有三种类型的附件,它们都扩展了一个名为 GenericAttachment
:
GenericAttachment
||
==> FormA_Attachment
==> FormB_Attachment
==> FormC_Attachment
我也有不同的表单类型,它们都扩展了一个名为 GenericForm
:
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
转换为动态选择 type
的 List<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>
。因此,您应该能够执行以下操作,而不是所有这些 if
s:
return ((IEnumerable<GenericAttachment>)attachments).ToList();