【问题标题】:Whats the cost of casting parameters铸造参数的成本是多少
【发布时间】:2012-03-08 00:00:38
【问题描述】:

在使用 MVVM 和 Prism 时,我发现自己做了很多转换,因为大多数参数都是接口

  public void AddCrSubSystemsToPlant(IPlantItem plantItm, CRArticleItem crItm)
        {

            OSiteSubSystem itm = (OSiteSubSystem)crItm;
            itm.PartData.Order = ((OSiteEquipment)plantItm).SubSystems.Count() + 1;

            ((OSiteEquipment)plantItm).SubSystems.Add(itm);

        }

  public void DeletePart(IPlantItem plantItem)
        {
            IEnumerable<IPlantItem> itmParent = GetParentPartByObjectId(_siteDocument, plantItem);

            if (plantItem is OSiteEquipment)
            ((ObservableCollection<OSiteEquipment>)itmParent).Remove((OSiteEquipment)plantItem);

            if (plantItem is OSiteSubSystem)
                ((ObservableCollection<OSiteSubSystem>)itmParent).Remove((OSiteSubSystem)plantItem);

            if (plantItem is OSiteComponent)
                ((ObservableCollection<OSiteComponent>)itmParent).Remove((OSiteComponent)plantItem);
        }

我的问题是,所涉及的费用是多少。如果避免这些操作,这些操作是否会占用大量内存或 CPU。

有什么意见吗?

【问题讨论】:

  • 为什么需要所有这些演员表?您的接口不公开所需的操作吗?如果没有,为什么不呢?
  • 你可以模拟一些有和没有强制转换的测试用例并测量性能。我不认为任何单独的演员都会对表演产生很大影响,但这取决于你这样做的频率。
  • 查看相关答案:stackoverflow.com/a/9366456/414076
  • 考虑使用as关键字作为强制转换不会抛出异常,而是返回null
  • 您还可以通过使用“as”而不是“is”,然后检查 null 来删除第二个代码 sn-p 中的重复强制转换。当然,由于您要检查多种类型,我不确定这是否真的会提供更好的性能。 [编辑:ja72 打败了我!]

标签: c# casting


【解决方案1】:

我认为更重要的问题是你为什么要做这么多选角?

在第一个例子中:
为什么第一个参数类型是IPlantItem,如果你一直把它转换成OSiteEquipment?第二个参数也一样。

在第二个例子中:
为什么 GetParentPartByObjectId 返回 IEnumerable&lt;IPlantItem&gt;?如果要返回 ICollection&lt;IPlantItem&gt;,则不必强制转换为 ObservableCollection&lt;T&gt;ObservableCollection&lt;T&gt; 继承自 Collection&lt;T&gt;,后者实现了 ICollection&lt;T&gt;ICollection。您应该能够在不知道其类型的情况下从集合中删除该项目。

现在有一些建议。
不要多次投射同一个对象。
不要这样做:

if (obj is IPlantItem)
    ((IPlantItem)obj).DoSomething();

改为这样做

IPlantItem plant = obj as IPlantItem;
if (plant != null)
    plant.DoSomething();

尽可能使用基本类型。这将使您无需进行如此多的投射。如前所述,不要强制转换为 ObserableCollection&lt;T&gt; 以调用 ICollection 上的方法

使用泛型。如果您需要特定于类型的逻辑,请使用泛型参数创建一个抽象基类(或者如果您不需要任何共享逻辑,则只需一个接口)。然后为接口的每个实现实现该类。方法也可以是通用的。我可以将第二个示例重写为

public void DeletePart<TPlantItem>(TPlantItem plantItem)
    where TPlantItem : IPlantItem
{
    IEnumerable<TPlantItem> itmParent = GetParentPartByObjectId(_siteDocument, plantItem);
    ((ObservableCollection<TPlantItem>)itmParent).Remove(plantItem);
}

【讨论】:

  • 当实现需要实际实现而不是接口的行为时,祝单元测试好运。
  • 这就是为什么我建议更改参数类型而不是强制转换和具有类型特定实现的通用抽象基类/接口。
  • 即使你给了 OP 他需要的东西,我认为给他想要的东西(“演员的成本是多少?”)至少简而言之还是不错的。
  • @svick Anthony Pegram 通过链接到这个答案 stackoverflow.com/a/9366456/414076 来解决这个问题
  • 感谢您的回答。我想实现 ICollection 但遗憾的是,即使 OSiteEquipment 实现接口 IPlantItem,我似乎也无法从 ObservableCollection 转换为 ICollection
【解决方案2】:

使用

       ((System.Collections.IList)itmParent).Remove(plantItem);

而不是

        if (plantItem is OSiteEquipment) 
        ((ObservableCollection<OSiteEquipment>)itmParent).Remove((OSiteEquipment)plantItem); 

        if (plantItem is OSiteSubSystem) 
            ((ObservableCollection<OSiteSubSystem>)itmParent).Remove((OSiteSubSystem)plantItem); 

        if (plantItem is OSiteComponent) 
            ((ObservableCollection<OSiteComponent>)itmParent).Remove((OSiteComponent)plantItem); 

【讨论】:

    【解决方案3】:

    这篇文章可能会阐明投射如何影响性能

    http://www.codeproject.com/Articles/8052/Type-casting-impact-over-execution-performance-in

    以下是一些基于 前几节得到的结果:

    • 数字类型转换通常很昂贵,将它们从循环和递归函数中取出,并在以下情况下使用相同的数字类型 可能。

    • 向下转换是一项伟大的发明,但所涉及的类型检查对执行性能有很大影响,请检查对象类型 循环和递归函数,并在其中使用“as”运算符。

    • 向上转型很便宜!在需要的地方使用它。

    • 构建轻量级转换运算符以更快地进行自定义转换。使用的工具

    【讨论】:

    • 我发现这些原则和结果中的大部分都是成立的,尽管这些数字可能已经过时了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多