我有以下示例代码。 Waht是最好的做法?比较值或比较类型以执行特定的业务逻辑:
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)
}
}
守则只是为了说明。
答案 0 :(得分:4)
鉴于这3个选项,我选择选项2
例如 - 尝试进行转化并检查它是否不是Null
。
它比最后一个选项更好的原因是选项3 会导致您进行2次转换,一次转换为is
,另一次转换为as
次转换线。
最后,选项1 是最糟糕的IMO - 它要求你拥有一些你不能确定以后会坚持的逻辑(没有人阻止有人创建客户具有Category
的CategoryA和CategoryName
的“B类”)。此外,这是一个额外的逻辑,可以通过选项2 以更清晰的方式完成。
我应该提及,正如其他评论/答案中所指出的,还有一些可以考虑的选项。使用 Polymorphism 可能是最好的设计策略。
答案 1 :(得分:3)
我认为你的设计有问题。这是一个smelly design IMO,可以进行多次检查和转换。
CategoryA catA = customer.Category as CategoryA;
if(catA != null)
{
DoSomething(catA)
}
所以大概你有一个DoSomething(CategoryA cat)
,DoSomething(CategoryB cat)
等等。
在这种情况下,我强烈建议您考虑将DoSomething
移至类别类。
customer.Category.DoSomething();
然后可以CategoryA
,CategoryB
和CategoryC
以不同方式实施。
如果只有CategoryA
的实现,则在基类中只有一个空实现,不要在B和C中覆盖。
额外建议:使用界面
我个人不会实现基本类型。我总是选择接口。当代码不在类层次结构的多个层中时,它的限制性更小,更容易理解。
public interface ICategory{
void DoSomething();
}
public class CategoryA : ICategory {...}
public class CategoryB : ICategory {...}
界面实施者之间的共同功能?没问题,只需创建一个新对象来执行该功能并将其组合到两个实现者中。然后,该功能可以单独进行单元测试。
答案 2 :(得分:1)
除了其他回答者关于表演或演员一次或两次或其他什么解释的其他要点之外,我还想做一些考虑。
这完全取决于业务在您的特定情况下会做什么:
不要使用类型。它应该是字符串,或Guid
或int
之类的标识符。您的UI本地化会将标识符转换为人类可读的名称。这足以区分按类别。
解决方案:客户将拥有CategoryName
属性。按Id
进行比较。
一个字:枚举。定义Category
枚举:
public enum Category { A, B, C }
if(customer.Category == Category.A)
{
// Whatever
}
解决方案: Customer
将拥有Category
属性。比较枚举值。
我不会为每个类别创建一个类。类别是实体,并且有零个或多个类别具有特定标识符或名称。
出于这个原因,Category
的{{1}}和Name
属性分别为Id
和string
或int
类型。
解决方案: Guid
与Customer
的关联为1:1,Category
属性为Category
。按Name
进行比较。
答案 3 :(得分:0)
根据您的情况,这有点主观。在我看来,最好按类型而不是字符串进行比较,因为你可以错误输入一个字符串,但编译器会检查你输错了类型。在选项2和3之间,除了跳过带有选项2的第二个演员之外,确实无关紧要。
答案 4 :(得分:0)
选项2始终优于选项3,因为它可以节省第二个演员阵容。因此,我们可以取消选项3。
对于选项1,我不得不问为什么要复制属性中的类型名称?这是冗余代码(因为您已经有了类型名称)。
因此,根据您描述的方案,选项2是最好的。但是,有关您正在检查的内容,更改的可能性,类别名称与类名称的紧密程度等相关的详细信息可能会影响决策......
答案 5 :(得分:0)
编辑3:
我认为在这个问题中,作者并不是说对象是POCO,因为如果Category
是POCO,那么它就不能是多态的。因此,从CategoryA
继承CategoryB
和Category
是没有意义的 - 为什么我们希望在没有多态的情况下拥有相同的接口?!所以结论是这个问题的作者犯了设计错误,或者他应该考虑我的原始答案。
编辑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");
}
}
答案 6 :(得分:0)
为什么不在父类中实现override方法:
public override bool Equals(System.Object obj)
{
bool equal=true;
//any kind of business logic here on the object values andor types
return equal;
}
我们一直这样做,效果很好:)。