1

我有以下示例代码。最佳做法是什么?比较值或比较类型以执行某种业务逻辑:

public Customer
{
    public Category {get;set;}
    public CategoryName {get;set;}  //e.g. "Category A" or "Category B"
}

public Category{}

public CategoryA : Category {}

public CategoryB : Category {}

public void Main()
{
    Customer customer = new Customer();

// Option 1:
if(customer.CategoryName == "Category A")
{
    CategoryA catA= customer.Category as CategoryA;     
    DoSomething(catA)
}

// Option 2:
CategoryA catA= customer.Category as CategoryA;
if(catA != null)
{
    DoSomething(catA)
}

// Option 3:
if(customer.Catgeory is Category A)
{
    CatgeoryA catA= customer.Category as CategoryA;
    DoSomething(catA)
}
}

本守则仅作说明之用。

4

7 回答 7

4

鉴于这 3 个选项,我会选择Option 2
例如 - 尝试进行转换并检查它是否不是Null

它比最后一个选项更好的原因是选项 3导致您进行 2 次转换,一个用于下一行is,一个用于as下一行。

最后,选项 1是最糟糕的 IMO - 它要求你有某种逻辑,你不能确定以后会坚持下去(没有人阻止某人创建具有Category类别 A 和CategoryName类别 B的客户”)。此外,这是额外的逻辑,可以通过Option 2以更清晰的方式完成。

我应该提到,正如其他评论/答案中所指出的那样,还有一些可以考虑的选项。使用多态可能是最好的设计策略。

于 2012-11-30T13:55:19.130 回答
3

我认为你的设计有问题。IMO 有多个检查和演员表是一个臭的设计。

CategoryA catA = customer.Category as CategoryA;
if(catA != null)
{
    DoSomething(catA)
}

所以大概你有一个DoSomething(CategoryA cat)DoSomething(CategoryB cat)等等。

在这种情况下,我强烈建议您考虑将DoSomething移至类别类。

customer.Category.DoSomething();

然后可以通过 和 以不同的方式CategoryA实现CategoryBCategoryC

如果只有一个实现CategoryA,则在基类中只有一个空实现,并且不要在 B 和 C 中覆盖。

额外推荐:使用接口

我个人不会实现基本类型。我总是选择接口。当代码不在多个类层次结构中时,它的限制较少且更容易遵循。

public interface ICategory{
  void DoSomething();
}

public class CategoryA : ICategory {...}

public class CategoryB : ICategory {...}

接口实现者之间的通用功能?没问题,只需创建一个新对象来执行该功能并将其组合到两个实现者中。然后可以单独对该功能进行单元测试。

于 2012-11-30T14:20:16.283 回答
1

除了其他回答者解释的关于性能或演员一两次或其他的其他观点,我想提出一些考虑。

这绝对取决于企业在您的特定情况下会做什么:

一个。类别只是一个鉴别器

不要使用类型。它应该是一个字符串,或者一个标识符,如 a Guidor int。您的 UI 本地化会将标识符转换为人类可读的名称。这足以区分类别

解决方案:客户将拥有CategoryName财产。比较Id

湾。类别是一个鉴别器,可能的类别数量有限

一个词:枚举。定义一个Category枚举:

public enum Category { A, B, C }

if(customer.Category == Category.A)
{
    // Whatever
}

解决方案:Customer将有一个Category属性。通过枚举值进行比较

C。类别是一个实体

我不会为每个类别创建一个类。类别是实体,有零个或多个具有特定标识符或名称的类别。

因此,分别Category具有and和or类型的NameandId属性。stringintGuid

解决方案:Customer将有一个 1:1 的关联Category并且Category会有一个Name属性。比较Id

于 2012-11-30T14:29:37.673 回答
0

编辑3:

我认为在这个问题中作者并不是说对象是 POCO,因为如果Category是 POCO,那么它就不能是多态的。CategoryA正因为如此,继承和继承是没有意义CategoryBCategory——为什么我们想要没有多态的相同接口?!所以结论是这个问题的作者犯了一个设计错误,或者他应该考虑我的原始答案。

编辑2:

我刚刚注意到,在Customer我们不知道具体类型的Category. 所以我们不能CategoryService用作:

new CategoryService().DoSomething(customer.Category); // compile-time error

所以编辑 1对这种情况无效。

编辑1:

因为POCO您可以使用带有方法重载的服务类:

public class Customer {
    public Category Category { get; set; }
}

public abstract class Category {
}

public class CategoryA : Category {
}

public class CategoryB : Category {
}

public class CategoryService {
    public void DoSomething(CategoryA c) {
        Console.WriteLine("A");
    }

    public void DoSomething(CategoryB c) {
        Console.WriteLine("B");
    }
}

原来的:

最佳做法是使用polymorphism. 当您需要比较类型时,这表明您做错了什么或者这是非常特殊的情况。

public class Customer {
    public Category Category { get; set; }
}

public abstract class Category {
    public abstract void DoSomething();
}

public class CategoryA : Category {
    public override void DoSomething()
    {
        Console.WriteLine("A");
    }
}

public class CategoryB : Category {
    public override void DoSomething()
    {
        Console.WriteLine("B");
    }
}
于 2012-11-30T14:05:05.277 回答
0

根据您的情况,这有点主观。在我看来,按类型而不是按字符串进行比较总是更好,因为您可能会错误地输入字符串,但编译器会检查您是否输入错误的类型。在选项 2 和 3 之间,除了使用选项 2 跳过第二次演员表之外,真的没有什么关系。

于 2012-11-30T13:57:33.917 回答
0

选项 2 总是比选项 3 好,因为它节省了第二次施法。因此,我们可以排除选项 3。

至于选项 1,我不得不问你为什么要在属性中复制类型名称?这是多余的代码(因为您已经有了类型名称)。

因此,考虑到您所描述的情况,选项 2 是最好的。但是,关于您正在检查的内容、更改的可能性、类别名称与类名称的关联程度等的更多细节可能会影响决定......

于 2012-11-30T13:57:35.773 回答
0

为什么不在父类中实现这样的覆盖方法:

public override bool Equals(System.Object obj)
{
    bool equal=true;

    //any kind of business logic here on the object values andor types

    return equal;
}

我们一直这样做,效果很好:)

于 2012-11-30T14:36:22.113 回答