如何重构以避免InvalidCastException?

How can I refactor this to avoid InvalidCastException?

提问人:juicejuiceeire 提问时间:4/5/2022 更新时间:4/5/2022 访问量:93

问:

基本上,我在这里寻找创建“PaymentPayloads”(自定义类型)列表,方法是查找具有有效 itemId 的 queueItems,然后将其转换为 PaymentPayload 项并将每个项添加到列表中。但是,对于此 Cast 错误,是否有另一种解决方案?

    var paymentPayloads = new List<PaymentPayload>();

    try
    {
         paymentPayloads = queueItems.Where(x => queueItemIds.Any(y => y == x.ItemId))
                             .Select(x => (PaymentPayload)x.Payload)
                             .ToList();
    }
    catch
    {
         throw new InvalidCastException();
    }

QueueItem 类具有类型为“PayloadBase”的字段“Payload”

    public PayloadBase Payload { get; set; }

我的 PaymentPayload 类像这样继承 PayloadBase

    public class PaymentPayload : PayloadBase

谁能告诉我为什么这个演员是无效的,以及我可以做的任何有效的替代方案?也许在某种foreach循环中创建一个新对象?

C# .NET Linq foreach 强制转换

评论

1赞 canton7 4/5/2022
不能将基类型的实例强制转换为其派生类型之一。如果字段不是从 继承的,并且您能够将 a 转换为 ,则这些字段将具有哪些值?PaymentPayloadPayloadBasePayloadBasePaymentPayload
0赞 Michael Schönbauer 4/5/2022
虽然“Upcasts”是可以的(抽象),但每当你有 Downcasts,你应该注意你是否有一个设计问题(“禁忌知识”)。
0赞 juicejuiceeire 4/5/2022
我认为是空白或默认值。
0赞 juicejuiceeire 4/5/2022
我应该为每个创建一个新的 PaymentPayload 而不是强制转换吗?
0赞 MakePeaceGreatAgain 4/5/2022
这不会有太大变化。当然,它避免了例外。但是,如果从基本对象到派生对象有意义,它不会改变。这是只有您才能适当处理的一点,因为我们不知道为什么对象首先是基本类型。

答:

0赞 JonasH 4/5/2022 #1

谁能告诉我为什么这个演员是无效的,以及我可以做的任何有效的替代方案?

强制转换无效,因为至少某些项的有效负载不是 类型。如果它不是抽象的,或者是其他一些派生类型,它可能是。调试器和/或 IDE 应该能够告诉您实际类型是什么以及派生自哪些类型。PaymentPayloadPayloadBasePayloadBase

如果您只想处理有效负载为 a 的项目,则可以使用PaymentPayload

.Select(x => x.Payload)
.OfType<PaymentPayload>()

但是没有办法判断这是否会给出正确的行为。

所有有效载荷都打算是吗?如果是这样,则应更改属性的类型。PaymentPayload

是否所有有效载荷都应属于同一类型,都派生自 ?然后,使用具有约束的泛型可能是合适的。PayloadBase

有效负载是否应具有多种混合类型?然后,您需要知道应该如何处理每种类型,而忽略所有其他类型而不是正确的行为,但只有您和您的同事了解应用程序的详细信息以及它的工作方式。PaymentPayload

当您向下转换对象时,即将 PayloadBase 强制转换为 PaymentPayload,而不是相反,您有意忽略类型系统为您提供的保护。从本质上讲,告诉编译器你知道的比它知道的更多。但是,这转移了确保类型与您匹配的责任。因此,在设计良好的代码中,直接强制转换往往相当罕见,更典型的方法是使用模式匹配

评论

0赞 juicejuiceeire 4/5/2022
“无法将类型为”PayloadBase“的对象转换为类型为”PaymentPayload”。是的,只有一个项目。在 PayloadBase 中只有一个字段,我希望能够将此字段从 PayloadBase 中写入新的 PaymentPayload
0赞 JonasH 4/5/2022
@juicejuiceeire听起来你想要类似 .但是你的问题不是很清楚。提供一个最小的可重现示例来说明您想要的内容可能会很有用。.Select(x => new PaymentPayload(x.Payload.MyProperty))