我有一个方法可以获得各种类型的object
。取决于type
的{{1}}我需要做不同的操作。我目前的代码是这样的:
object
我对这段代码不太满意,因为我有一些不必要的演员表。哪种操作最有效?我在考虑类似的事情:
public void SomeMethod(object obj)
{
int? someId = null;
Class1 class1 = obj as Class1;
Class2 class2 = obj as Class2;
Class3 class3 = obj as Class3;
Class4 class4 = obj as Class4;
if (class1 != null && class1.SomeProperty != null)
{
someId = class1.SomeProperty.Id;
}
else if (class2 != null && class2.AnotherProperty != null)
{
someId = class2.AnotherProperty.AnotherId;
}
...
AnotherMethod(someId);
}
有什么建议吗?
答案 0 :(得分:5)
两种选择都非常糟糕,因为它们会进行显式转换,并通过手动检查类型进行调度。这很容易出错,当您展开方法需要处理的类型列表时,会导致不可避免的维护问题。
从.NET 4.0开始,您有一个更好的选择 - 使用dynamic
发送:
public void SomeMethod(dynamic obj) {
SomeMethodImpl(obj);
}
private void SomeMethodImpl(Class1 obj) {
// Perform actions specific to Class 1
}
private void SomeMethodImpl(Class2 obj) {
// Perform actions specific to Class 2
}
private void SomeMethodImpl(Class3 obj) {
// Perform actions specific to Class 3
}
private void SomeMethodImpl(Class4 obj) {
// Perform actions specific to Class 4
}
private void SomeMethodImpl(object obj) {
// Catch all
}
现在,您可以将特定于类的代码放在其自己的SomeMethodImpl
重载中,而无需运行条件语句链。扩展处理其他类型的方法也很简单 - 您只需要添加另一个重载。
注意:我认为SomeMethod
的签名必须保持不变 - 换句话说,您无法通过重载 {{1来解决此问题}}
答案 1 :(得分:2)
我认为你应该首先尝试这样做而不进行投射。您可以定义接口并为每个Classn
显式实现此接口。我假设Classn
类不是第三方,你可以修改它们。
public interface IIdProvider {
int? Id { get; }
}
public class Class1 : IIdProvider {
int? IIdProvider.Id {
get {
return SomeProperty != null ? SomeProperty.Id : null;
}
}
}
public class Class2 : IIdProvider {
int? IIdProvider.Id {
get {
return AnotherProperty != null ? AnotherProperty.AnotherId : null;
}
}
}
有了这个,SomeMethod
并不关心Id的来源。如果您想添加Class5
,Class6
等,则无需修改SomeMethod
。相反,每个新添加的类都将处理Id
事物本身。有了这个,我们可以做到以下几点。
public void SomeMethod(IIdProvider obj)
{
AnotherMethod(obj.Id);
}
答案 2 :(得分:2)
多态?
public void SomeMethod(Class1 class1)
{
AnotherMethod(class1.SomeProperty.Id);
}
public void SomeMethod(Class2 class2)
{
AnotherMethod(class2.NewProperty.Id);
}
.
.
.
相反,为什么不直接拨打AnotherMethod(class1.SomeProperty.Id);
,.. AnotherMethod(class2.NewProperty.Id)
,如果这就是你想做的......
如果你真的想检查对象是否属于某种类型,请使用if(obj is Class1)
而不是强制转换
答案 3 :(得分:1)
在这种特殊情况下(获取变量的单个值),使用类似开关的方法可能更有效,例如:
public int? GetSomeId(object obj) {
Class1 class1 = obj as Class1;
if (class1 != null)
{
return class1.SomeProperty != null ? class1.SomeProperty.Id : (int?)null;
}
Class2 class2 = obj as Class2;
if (class2 != null)
{
return class2.AnotherProperty != null ? class2.AnotherProperty.AnotherId : (int?)null;
}
....
return null;
}
答案 4 :(得分:0)
as
关键字。它被翻译为
Class1 class1 = obj is Class1 ? (Class1)obj : null;
我认为使用as
,因为它看起来更具可读性,也不会影响性能。
答案 5 :(得分:0)
我会用:
if (obj is Class1 && ((Class1)obj).SomeProperty)
someId = ((Class1)obj).SomeProperty.Id;
最终代码如下所示:
if (obj is Class1 && ((Class1)obj).SomeProperty)
someId = ((Class1)obj).SomeProperty.Id;
else if (obj is Class2 && ((Class2)obj).AnotherProperty)
someId = ((Class2)obj).AnotherProperty.Id;
else if (obj is Class3 && ((Class3)obj).OnceAgainAnotherProperty)
...
在每个if
和else if
条件下,如果第一次检查obj is X
失败,则不会执行第二次((X)obj).XProperty
。因此,在一天结束时,即使您的对象为Class4
类型,也只会执行两次演员表。