2011-11-17 59 views
2

我有一个实现一个(自定义)接口的对象集合:IAuditEvent通过枚举属性而不是使用GetType()来识别对象类型是否很糟糕?

每个对象都可以存储在数据库中,并且每个对象类型都使用唯一的数字ID。

存储对象的方法围绕着List<IAuditEvent>循环,因此它需要知道每个对象的具体类型才能存储正确的数字ID。

IAuditEvent上拥有枚举属性是否很差吗?以便每个对象都可以使用唯一的枚举值标识其类型?

我可以看到最简单的解决方案是编写一个将Type转换为整数的方法,但是如果我需要枚举审计事件以用于其他目的呢?在IAuditEvent上有我的枚举属性是否仍然是错误的?

+0

为了让'IAuditEvent'的成员识别特定类型的事件,为什么不好的做法是?潜在的问题是什么? –

+0

哈哈!那就是我要问的。 ;-)我想有些人会争辩说,你给对象2种不同的方式来识别自己,而这2种方式可能会有不同意见。 – James

+0

“通过枚举属性标识对象”是什么意思? GetType()可用于识别对象的类型,而不用于识别对象本身...... – user1027167

回答

2

这个数据库类型ID(或鉴别)本质上是每种类型的元数据。在每个实例上混合数据和元数据并不好。我的首选解决方案是编写一个自定义属性来保存此元数据,将其应用于每种类型,并使用TypeGetCustomAttributes方法读取这些元数据。

[DatabaseDiscriminator(123)] 
public class MyAuditEvent : IAuditEvent 
{ 
} 
+0

如果开发人员忘记添加自定义属性,会发生什么情况?你能在编译时捕捉到吗? – James

+0

不,它必须是运行时异常。我认为这不是一个巨大的缺点。毕竟,开发人员可以实现一个接口,但将适当的方法保留为'throw new NotImplementedException()'。 –

+0

是的,的确如此。我可以使用反射来检查实现'IAuditEvent'的每个对象是否具有自定义属性?我的应用程序已经运行了一系列“自我测试”(更多关注数据库配置,但没有理由不能检查这一点)。 – James

1

是的,这是不好的。您现在假设IAudit的每个实现都知道其他实现,因为它们都应具有唯一的ID;此外,您需要为接口的每个新实例添加一个新值到enum。这只是应用程序内部不需要的额外信息,但只是在数据表示中。

而是有一个查找表在业务层:

new Dictionary<Type, int> { 
    { typeof(UserAudit), 1 }, 
    { typeof(OrderAudit), 2 } 
} 
+0

“是的,这很糟糕” - 我想这可能是! – James

1

简答:取决于。

请记住接口的用途。它们的全部重点是将实现隐藏到接口的用户。当谈到接口我看到两种类型的代码:

代码使用接口。这段代码应该只知道IAuditEvent,而不是它的实现类。如果这段代码需要知道不同类型的审计事件(我的意思是“最常用的类型”,而不是专门的类),那么我认为向IAuditEvent添加一个Type属性是一个好习惯。就用户而言,甚至不需要针对每种类型实施不同的实施。

另一种类型的代码是实现接口的代码,我的意思不仅仅是继承自IAuditEvent的类,还包括构造并意味着直接与这些实现一起使用的类。如果这个和只有这代码需要知道它处理的是什么类型的IAuditEvent(这里我的意思是在类中类型),那么我会说这是不好的做法,添加一个Type属性,因为它暴露了位实施。这个代码可以做一个实例检查。

+0

一个有用的回复,谢谢。我开始怀疑我是否可能以错误的方式解决我的问题。 – James

0

实现接口的目的是抽象出实现 - IOW使用接口并且不关心实现类型,因此不需要用枚举值来标识它。

话虽如此,我会做的方式是有一个共同的基本类型,其既实现了接口,并有一个返回枚举抽象属性:

public abstract class BaseType : IAuditEvent 
{ 
    public abstract MyTypeEnum TypeId { get; } 

    ... add any base implementation of the interface ... 
} 

然后在每个派生对象:

public class MyConcreteType : BaseType 
{ 
    public MyTypeEnum TypeId { get { return MyTypeEnum.SpecificValue; } } 

    ... any overrides, etc .... 
} 

这种方法有两个优点:

  • 它记ps清理你的代码。当在许多类中实现接口时,很可能会有一些接口的通用实现,即不同的对象可以共享的接口,可以放在基类中。明智地使用abstractvirtual方法/属性。

  • 使用枚举来识别你的对象可以帮助避免那些无休止的,繁琐if (myObj.GetType() == typeof(ObjectA)) {} else if (myObject.GetType() == typeof(ObjectB))...语句,当谈到时间根据实施者的类型分支 - 现在你可以使用switch语句基于返回的枚举TYPEID财产

你仍然会留下有延长枚举你应该增加更多实现的问题,但这是一个相对简单的代码改变,你必须recomplie无论如何,如果要添加更多的实现(所以扩展枚举不是什么大问题,但是如果可能的话,你确实想避免改变已经赋值的值)。

相关问题