2

这个问题是关于铸造中的“是”“作为”以及关于CA1800 PostSharp规则的问题。我想知道我认为的解决方案是否是最好的解决方案,或者它是否有任何我看不到的问题。

我有这个代码(命名为原始代码并减少到最低相关)。ValidateSubscriptionLicenceProducts 函数尝试通过强制转换并稍后检查一些内容(在 //Do What 中)来验证 SubscriptionLicence(可能是 3 种类型:Standard、Credit 和 TimeLimited)。

PostSharp 抱怨 CA1800:DoNotCastUnnecessarily。原因是我将同一对象两次转换为同一类型。此代码在最佳情况下将转换 2 次(如果它是 StandardLicence),在最坏情况下将转换 4 次(如果它是 TimeLimited 许可证)。我知道有可能使规则无效(这是我的第一种方法),因为这里的性能没有太大影响,但我正在尝试一种最佳方法。

 //Version Original Code
  //Min 2 casts, max 4 casts
  //PostSharp Complains about CA1800:DoNotCastUnnecessarily
  private void ValidateSubscriptionLicenceProducts(SubscriptionLicence licence)
        {
   if (licence is StandardSubscriptionLicence)
            {               
                // All products must have the same products purchased
                List<StandardSubscriptionLicenceProduct> standardProducts = ((StandardSubscriptionLicence)licence).SubscribedProducts;
                //Do whatever
            }
            else if (licence is CreditSubscriptionLicence)
            {               
                // All products must have a valid Credit entitlement & Credit interval
                List<CreditSubscriptionLicenceProduct> creditProducts = ((CreditSubscriptionLicence)licence).SubscribedProducts;
                //Do whatever
            }
            else if (licence is TimeLimitedSubscriptionLicence)
            {                
                // All products must have a valid Time entitlement
                // All products must have a valid Credit entitlement & Credit interval
                List<TimeLimitedSubscriptionLicenceProduct> creditProducts = ((TimeLimitedSubscriptionLicence)licence).SubscribedProducts;
                //Do whatever 
            }
            else
                throw new InvalidSubscriptionLicenceException("Invalid Licence type");

   //More code...


        }

这是使用"as"的改进版本。不要抱怨 CA1800,但问题是它总是会投射 3 次(如果将来我们有 30 或 40 种类型的许可证,它可能会表现不佳)

    //Version Improve 1
  //Minimum 3 casts, maximum 3 casts
  private void ValidateSubscriptionLicenceProducts(SubscriptionLicence licence)
        {
      StandardSubscriptionLicence standardLicence = Slicence as StandardSubscriptionLicence;
            CreditSubscriptionLicence creditLicence = Clicence as CreditSubscriptionLicence;
            TimeLimitedSubscriptionLicence timeLicence = Tlicence as TimeLimitedSubscriptionLicence;

   if (Slicence == null)
            {               
                // All products must have the same products purchased
                List<StandardSubscriptionLicenceProduct> standardProducts = Slicence.SubscribedProducts;
                //Do whatever
            }
            else if (Clicence == null)
            {               
                // All products must have a valid Credit entitlement & Credit interval
                List<CreditSubscriptionLicenceProduct> creditProducts = Clicence.SubscribedProducts;
                //Do whatever
            }
            else if (Tlicence == null)
            {                
                // All products must have a valid Time entitlement
                // All products must have a valid Credit entitlement & Credit interval
                List<TimeLimitedSubscriptionLicenceProduct> creditProducts = Tlicence.SubscribedProducts;
                //Do whatever 
            }
            else
                throw new InvalidSubscriptionLicenceException("Invalid Licence type");

   //More code...
        }

但后来我想了一个最好的。这是我正在使用的最终版本。

    //Version Improve 2
// Min 1 cast, Max 3 Casts
// Do not complain about CA1800:DoNotCastUnnecessarily
private void ValidateSubscriptionLicenceProducts(SubscriptionLicence licence)
        {
            StandardSubscriptionLicence standardLicence = null;
            CreditSubscriptionLicence creditLicence = null;
            TimeLimitedSubscriptionLicence timeLicence = null;

            if (StandardSubscriptionLicence.TryParse(licence, out standardLicence))
            {
                // All products must have the same products purchased
                List<StandardSubscriptionLicenceProduct> standardProducts = standardLicence.SubscribedProducts;
    //Do whatever
            }
            else if (CreditSubscriptionLicence.TryParse(licence, out creditLicence))
            {
                // All products must have a valid Credit entitlement & Credit interval
                List<CreditSubscriptionLicenceProduct> creditProducts = creditLicence.SubscribedProducts;
                //Do whatever
            }
            else if (TimeLimitedSubscriptionLicence.TryParse(licence, out timeLicence))
            {
                // All products must have a valid Time entitlement
                List<TimeLimitedSubscriptionLicenceProduct> timeProducts = timeLicence.SubscribedProducts;
                //Do whatever
            }
            else
                throw new InvalidSubscriptionLicenceException("Invalid Licence type");

            //More code...

        }


    //Example of TryParse in CreditSubscriptionLicence
  public static bool TryParse(SubscriptionLicence baseLicence, out CreditSubscriptionLicence creditLicence)
        {
            creditLicence = baseLicence as CreditSubscriptionLicence;
            if (creditLicence != null)
                return true;
            else
                return false;
        }

它需要更改 StandardSubscriptionLicence、CreditSubscriptionLicence 和 TimeLimitedSubscriptionLicence 类以具有“tryparse”方法(在下面的代码中复制)。这个版本我认为它最少只能投射一次,最多只能投射三个。改进2你怎么看?有没有最好的方法呢?

4

2 回答 2

4

在您的三个代码片段中,“改进 2”似乎是最好的一个。但是,我认为您可以通过完全消除铸造需求的方式改进您的设计。

添加一个调用的抽象方法ValidateProductsSubscriptionLicence并让每个子许可证实现特定于该特定类型许可证的逻辑。这样,您可以将业务逻辑与数据一起放置,从而避免出现贫乏的领域模型

这样,您的方法的实现将仅仅是:

private void ValidateSubscriptionLicenceProducts(SubscriptionLicence licence)
{
    if(!licence.ValidateProducts())
        throw new Exception("Failed to validate products");
}

此外,通过在基类上使方法抽象,您强制执行每个“子许可证”来实现该方法,因此您无需检查任何内容。因此,ValidateSubscriptionLicenceProducts即使将来添加新类型的许可证,也永远不必更改该方法。

希望这是有道理的。

于 2010-04-08T10:44:54.173 回答
0

我不认为 PostSharp 抱怨。而是 FxCop。

于 2010-04-08T10:54:02.367 回答