当前位置: 首页 > 编程语言 > C#

C#-.Net中“新”属性的优缺点?分享

时间:2023-04-10 15:20:15 C#

C#/.Net中“新”属性的优缺点?考虑以下示例代码://交付策略publicabstractclassDeliveryStrategy{...}publicclassParcelDelivery:DeliveryStrategy{...}publicclassShippingContainer:DeliveryStrategy{...}和以下示例Order类://order(base)classpublicabstractclassOrder{privateDeliveryStrategy交付;protectedOrder(DeliveryStrategydelivery){this.delivery=delivery;}publicDeliveryStrategyDelivery{get{退货;}protectedset{交付=值;当我派生一个新类型的订单类时,它会继承DeliveryStrategy类型的Delivery属性。现在,如果必须使用ParcelDelivery策略交付CustomerOrders,我们可以考虑在CustomerOrder类中使用“新”交付属性:'new'Delivery属性publicnewParcelDeliveryDelivery{get{returnbase.DeliveryasParcelDelivery;}set{base.Delivery=value;}}}(CustomerOrder显然需要确保与Order(多态)兼容)这允许直接在CustomerOrder上使用ParcelDelivery策略,而无需转换。您会考虑使用这种模式吗?为什么/为什么不?更新:我想出了这个模式而不是使用泛型,因为我想将它用于多个属性。我不想为所有这些属性使用泛型类型参数,我认为这是一个很好的模式。通过消除转换结果的需要,它使显式使用派生类型变得更容易,并且它不会“破坏”基类行为。事实上,在BCL中的一些类中使用了类似的模式,例如,看DbConnection类层次结构:所以如果你通过DbConnection变量操作连接对象,CreateCommand会返回一个DbCommand;如果您通过SqlConnection变量操作它,CreateCommand将返回一个SqlCommand,如果您将它分配给SqlCommand变量,请避免使用它。我更喜欢使类型通用:publicabstractclassOrderwhereTDelivery:Delivery{publicTDeliveryDelivery{...}...}publicclassCustomerOrder:Order{...}这确保了编译时类型安全,而不是保留它执行时间。它还可以防止以下情况:CustomerOrdercustomerOrder=newCustomerOrder();订单order=customerOrder;order.Delivery=newNonParcelDelivery();//成功!ParcelDeliverydelivery=customerOrder.Delivery;//返回null我认为新的通常是最后的手段。它在实施和使用方面引入了额外的复杂性。如果您不想走通用路线,我将介绍一个真正的新属性(具有不同的名称)。您可以使用泛型。//订单(基)类publicabstractclassOrderwhereTDeliveryStrategy:DeliveryStrategy{privateTDeliveryStrategydelivery;protectedOrder(TDeliveryStrategydelivery){this.delivery=delivery;}publicTDeliveryStrategyDelivery{proget{returnset=delivery;;}}}publicclassCustomerOrder:Order{publicCustomerOrder():base(newParcelDelivery()){}}在我看来,使用“new”关键字隐藏基类中的可写属性不是一个好主意。new关键字允许您在派生类中隐藏基类的成员而不是覆盖它。这意味着使用基类引用调用这些成员仍然访问基类代码,而不是派生类代码。C#具有“virtual”关键字,它允许派生类实际覆盖实现,而不是简单地隐藏它。这是一篇讨论差异的非常好的文章。在您的情况下,您似乎正在尝试使用方法隐藏作为向C#引入属性协变的一种方式。但是,这种方法存在一个问题。通常,拥有基类的价值在于允许代码的用户以多态方式处理类型。如果有人使用对基类的引用设置Delivery属性,您的实现会怎样?如果Delivery属性不是ParcelDelivery的实例,派生类会中断吗?对于此实施选择,这些是您需要问自己的问题。现在,如果基类中的Delivery属性不提供setter,则您的情况略有不同。基类的用户只能检索属性而不能设置它。由于您将属性访问路由回基类,因此通过基类进行访问仍然有效。但是,如果派生类不是密封的,则从它们继承的类可能会通过将Delivery属性隐藏为自己的版本而引入相同类型的问题。正如在其他一些帖子中已经提到的,您可以使用泛型来实现不同的交付属性类型。Jon的例子很好地证明了这一点。如果您需要从CustomerOrder派生并将Delivery属性更改为新类型,那么泛型方法就会出现问题。有一种替代仿制药的方法。你需要考虑你是否真的想要一个可设置的属性。如果去掉Delivery属性的设置器,使用Order类引入的问题就会消失。由于您使用构造函数参数设置交付属性,因此所有订单都保证具有正确的策略类型。有什么理由需要更改返回类型吗?如果不是,那么我建议只将delivery属性设置为虚拟的,因此它必须由继承类定义:publicabstractclassOrder{protectedOrder(DeliveryStrategydelivery){}publicvirtualDeliveryStrategyDelivery{get;保护集;}}publicclassCustomerOrder:Order{publicCustomerOrder():base(newParcelDelivery()){}publicDeliveryStrategyDelivery{get;保护集;如果你确实需要改变返回类型,那么我想知道为什么你需要改变返回类型的行为。无论如何,如果是这样,那么这对你不起作用。所以要直接回答你的问题,我只会使用你描述的模式,如果返回类型需要与基类不同,我会非常谨慎(我会分析我的对象模型,看看是否还有其他我可以做的事情先做)。如果没有,那么我会使用上面描述的模式。考虑这种方法:publicinterfaceIOrder{publicDeliveryStrategyDelivery{get;}}//订单(基)类publicabstractclassOrder:IOrder{protectedreadonlyDeliveryStrategydelivery;protectedOrder(DeliveryStrategydelivery){this.delivery=delivery;}publicDeliveryStrategyDelivery{get{退货;}}}然后使用publicclassCustomerOrder:Order{publicCustomerOrder():base(newParcelDelivery()){}publicParcelDeliveryDelivery{get{return(ParcelDelivery).Delivery;根据;}}DeliveryStrategyIOrder.Delivery{get{returnbase.Delivery}}}这还远非完美(你的例子没有说明为什么基类需要知道交付策略,使用受约束的泛型会更有意义但这至少允许您对属性使用相同的名称并获得类型安全。在您的示例中,这是毫无意义的,如果某些东西不是正确的类型,您不应该用null覆盖它,您应该丢弃您的不变量。在可能的情况下,只读字段总是更好。它们使不变性变得清晰。您的解决方案并没有按照您的想法进行。它似乎有效,但它不会调用您的“新”方法。考虑对您的代码进行以下更改以添加一些输出以查看调用了哪个方法://order(base)classpublicabstractclassOrder{privateDeliveryStrategydelivery;protectedOrder(DeliveryStrategydelivery){this.delivery=delivery;}publicDeliveryStrategyDelivery{get{Console.WriteLine("Order");退货;}protectedset{交付=值;}}}publicclassCustomerOrder:Order{publicCustomerOrder():base(newParcelDelivery()){}//'new'Delivery属性publicnewParcelDeliveryDelivery{get{Console.WriteLine("CustomOrder");返回base.Delivery作为ParcelDelivery;}set{base.Delivery=value;然后使用以下代码片段实际使用您的CustomOrder类:Ordero=newCustomerOrder();vard=o.交货;将输出“订单”。新方法专门打破了多态性。它在CustomOrder上创建了一个新的Delivery属性,它不是Order基类的一部分。因此,当您将CustomOrder当作Order使用时,您不会调用新的Delivery属性,因为它只存在于CustomOrder上,而不是Order类的一部分。您所做的是覆盖不可覆盖的方法。如果您指的是要覆盖的属性,请将其抽象化://order(base)classpublicabstractclassOrder{privateDeliveryStrategydelivery;protectedOrder(DeliveryStrategydelivery){this.delivery=delivery;}publicabstractDeliveryStrategyDelivery{get{退货;}protectedset{交付=值;}}}publicclassCustomerOrder:Order{publicCustomerOrder():base(newParcelDelivery()){}publicoverrideParcelDeliveryDelivery{get{returnbase.DeliveryasParcelDelivery;}set{base.Delivery=value;}}}使用new来隐藏基类的虚拟成员是个坏主意,因为子派生类型将无法正确覆盖它们。如果派生类中有要影响的类成员,则不应将基类成员声明为abstract或virtual,而只需调用protectedabstract或protectedvirtual成员即可。派生类型可以使用调用相应受保护成员并适当转换结果的方法来隐藏基类方法。以上就是C#学习教程:C#/.Net中“新”属性的优缺点?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: