如何在c#中有条件地转换为多个类型

我正在看这个模式的函数:

if( obj is SpecificClass1 ) { ((SpecificClass1)obj).SomeMethod1(); } else if( obj is SpecificClass2 ) { ((SpecificClass2)obj).SomeMethod2(); } else if( obj is SpecificClass3 ) { ((SpecificClass3)obj).SomeMethod3(); } 

并获得代码分析警告:CA1800不要不必要地投射。

什么是一个很好的代码模式,我可以使用它代替这个代码将是高性能和简洁。

更新

我没有说,但obj是用类型对象声明的。

我原来在这里问了两个问题。 我已经拆了一个(无论如何还没有人回答): 为什么编译器不会将这两个演员优化为一个?

为避免双重铸造,您可以执行以下操作

 var objClass1= obj as SpecificClass1; if(objClass1!=null) objClass1.SomeMethod1(); 

关于模式,您可以使所有这些类实现一个公共接口,并使您的方法接收接口。

 public void SomeMethod(ISpecificInterface specific) { specific.SomeMethod1(); } 

你能在这做这样的事吗?

 interface IBaseInterface { void SomeMethod(); } public class Implementer1:IBaseInterface { public void SomeMethod() { throw new NotImplementedException(); } } public class Implementer2 : IBaseInterface { public void SomeMethod() { throw new NotImplementedException(); } } public class Implementer3 : IBaseInterface { public void SomeMethod() { throw new NotImplementedException(); } } 

然后,在调用者代码中:

 IBaseInterface concrete = GetInstance(); concrete.SomeMethod(); 

GetInstance将根据条件创建类对象。

你的类可以像这样inheritance一个ISomeMethodInterface:

  public interface ISomeMethodInterface { void SomeMethod(); } public class SpecificClass1 : ISomeMethodInterface { //some code public void SomeMethod() { } } public class SpecificClass2 : ISomeMethodInterface { //some code public void SomeMethod() { } } public class SpecificClass3 : ISomeMethodInterface { //some code public void SomeMethod() { } } 

在你的电话中:

 ((ISomeMethodsInterface)obj).SomeMethod(); 

接口

最好的方法是引入所有类型实现的接口。 只有在签名匹配(或者您没有太多差异)时才可以这样做。

使用as

如果创建接口不是一个选项,则可以使用以下模式删除CA消息(尽管这也会引入不必要的强制转换,因此会降低性能):

 var specClass1 = obj as SpecificClass1; var specClass2 = obj as SpecificClass2; var specClass3 = obj as SpecificClass3; if(specClass1 != null) specClass1.SomeMethod1(); else if(specClass2 != null) specClass2.SomeMethod2(); else if(specClass3 != null) specClass3.SomeMethod3(); 

您也可以将其更改为此结构(从我的角度来看,上面的可读性更好):

 var specClass1 = obj as SpecificClass1; if (specClass1 != null) specClass1.SomeMethod1(); else { var specClass2 = obj as SpecificClass2; if (specClass2 != null) specClass2.SomeMethod2(); else { var specClass3 = obj as SpecificClass3; if (specClass3 != null) specClass3.SomeMethod3(); } } 

在字典中注册类型

此外,如果您要检查多种类型,可以在字典中注册它们并检查字典的条目:

 var methodRegistrations = new Dictionary act>(); methodRegistrations.Add(typeof(SpecificClass1), x => ((SpecificClass1)x).SomeMethod1()); methodRegistrations.Add(typeof(SpecificClass2), x => ((SpecificClass2)x).SomeMethod2()); methodRegistrations.Add(typeof(SpecificClass3), x => ((SpecificClass3)x).SomeMethod3()); var registrationKey = (from x in methodRegistrations.Keys where x.IsAssignableFrom(obj.GetType()).FirstOrDefault(); if (registrationKey != null) { var act = methodRegistrations[registrationKey]; act(obj); } 

请注意,注册很容易扩展,您还可以在操作中调用具有不同参数的方法。

最可扩展的解决方案可能是inheritance具体类,同时实现具有SomeMethod实现的接口,该实现在inheritance的类上调用正确的SomeMethodx方法。 这样,您将保留现有界面,同时仍保留现有方法。

 public interface ISomething { void SomeMethod(); } public SpecificClass1Wrapper : SpecificClass1, ISomething { void SomeMethod() { SomeMethod1(); } } 

如果对象在它们存储在对象引用中之前以这种方式包装,则对SomeMethod()和对SomeMethod()的调用将替换整个if / else组合。

另一方面,如果对象来自代码,你无法扩展和简洁,但仍然清楚你要去做什么,你可以创建一个简单的帮助方法;

 private bool CallIfType(object obj, Action action) where T : class { var concrete = obj as T; if (concrete == null) return false; action(concrete); return true; } 

然后,您可以将调用编写为简单表达式;

 var tmp = CallIfType(obj, x => x.SomeMethod1()) || CallIfType(obj, x => x.SomeMethod2()) || CallIfType(obj, x => x.SomeMethod3()); if(tmp) Console.WriteLine("One of the methods was called"); 

好吧,有点粗糙,但是:

  public class BaseClass{} public class SubClass1 : BaseClass { public void SomeMethod1() { } } public class SubClass2 : BaseClass { public void SomeMethod2() { } } public class Class1 { public Class1() { var test = new SubClass1(); var lookup = new Dictionary> { {typeof (SubClass1), o => ((SubClass1) o).SomeMethod1() }, {typeof (SubClass2), o => ((SubClass2) o).SomeMethod2() } }; //probably best to check the type exists in the dictionary first, //maybe wrap up the execution into a class of it's own so it's abstracted away lookup[test.GetType()](test); } } 

写一个方法怎么样?

 public static class ObjectExtensions { public static bool TryCast(this object from, out T to) where T : class { to = from as T; return to != null; } } 

并使用它:

 SpecificClass1 sc1; SpecificClass2 sc2; SpecificClass3 sc3; if( obj.TryCast(out sc1) ) { sc1.SomeMethod1(); } else if( obj.TryCast(out sc2) ) { sc2.SomeMethod2(); } else if( obj.TryCast(out sc3) ) { sc3.SomeMethod3(); }