C# if(obj是thisObj)语句太多
我目前有一种方法,试图找出它收到的目标是什么。它知道它在某个接口上,例如iSeries,但我有代码查看它,并试图告诉我它是例如Service1还是Service2。 我目前有很多if(obj是thisObj)风格的语句,要使代码变得漂亮,最好的解决方案是什么 以下是我所拥有的一个样本:C# if(obj是thisObj)语句太多,c#,C#,我目前有一种方法,试图找出它收到的目标是什么。它知道它在某个接口上,例如iSeries,但我有代码查看它,并试图告诉我它是例如Service1还是Service2。 我目前有很多if(obj是thisObj)风格的语句,要使代码变得漂亮,最好的解决方案是什么 以下是我所拥有的一个样本: public void DoSomething(IService service) { if (service is Service1) {
public void DoSomething(IService service)
{
if (service is Service1)
{
//DO something
}
if (service is Service2)
{
//DO something else
}
}
现在拥有两个并不是一件坏事,但我希望拥有20多个这样的东西,使用起来会很糟糕
有什么想法吗
好的,我认为需要更多的细节,如下所示: 在此方法之前,我有另一个方法,它接收xml文档,并将其反序列化到接口IService中,因此我们有如下内容:
private static void Method(InnerXml)
{
var messageObj = (IServiceTask)XmlSerialization.Deserialize(typeof(IServiceTask), InnerXml);
var service = GetService(messageObj);
service.PerformTask(xmlDoc);
}
private static IService GetService(IServiceTask messageObj)
{
var service = new IService ();
if (messageObj is Task1)
{
service = (SomeService)messageObj;
}
if (messageObj is Task2)
{
service = (SomeOtherService)messageObj;
}
return service ;
}
希望这能让它更清楚一点。好吧,这取决于
//行在做什么。在某些情况下,最好在服务接口中声明一个方法,并将这些操作的逻辑放在服务本身中
另一方面,有时,服务本身不应该知道这些代码——在这一点上,生活会变得更加丑陋:(有时这类事情真的很难避免。我偶尔发现,泛型和lambda表达式的混合使用会有所帮助,例如
ConditionallyExecute<Service1>(service, s1 => s1.CallSomeService1Method());
ConditionallyExecute<Service2>(service, s2 => s2.CallSomeService2Method());
...
…但是当我这么做的时候,我真的很不高兴:(你能改变iSeries设备吗
添加方法DoSomething()
并在所有服务中实现它。这并不能使它更好地阅读,但可能会更好地执行(如果一个服务不能同时是两种类型):
另一种方法
也许这也是一个可能的解决方案:
private Dictionary<Type, Action<object>> _TypeExecutor;
private void SetupExecutors()
{
_TypeExecutor = new Dictionary<Type, Action<object>>();
_TypeExecutor.Add(typeof(Service1), new Action<object>((target) => target.DoSomething()));
_TypeExecutor.Add(typeof(Service2), new Action<object>((target) =>
{
var instance = (Service2)target;
var result = instance.DoSomething();
}));
_TypeExecutor.Add(typeof(Service3), AnotherMethod);
}
private void AnotherMethod(object target)
{
var instance = (Service3)target;
var result = instance.DoSomething();
}
private void DoWork(ISomething something)
{
Action<object> action;
if (_TypeExecutor.TryGetValue(something.GetType(), out action))
{
action(something);
}
}
private Dictionary\u TypeExecutor;
私有无效设置执行器()
{
_TypeExecutor=新字典();
_TypeExecutor.Add(typeof(Service1),新操作((target)=>target.DoSomething());
_TypeExecutor.Add(typeof(Service2),新操作((目标)=>
{
var实例=(Service2)目标;
var result=instance.DoSomething();
}));
_TypeExecutor.Add(typeof(Service3),另一种方法);
}
私有void AnotherMethod(对象目标)
{
var实例=(Service3)目标;
var result=instance.DoSomething();
}
私人空嫁妆(某物)
{
行动;
if(_TypeExecutor.TryGetValue(something.GetType(),out操作))
{
行动(某物);
}
}
我喜欢在这些场景中使用字典
Dictionary<Type,Action<IService>>
字典
如果您自己编写服务类,那么接口就是最好的选择。如果应该对对象调用Foo(),如果它是Service1或Service2,那么它们应该实现一个公共接口,您只需检查它是否是这两个接口中的一个,然后运行相关代码
但是,如果他们的课程不能改变,那么我认为你运气不好。20+完全不同的课程,应该有20+完全不同的逻辑应用于他们,必须简单地…以不同的方式处理
还是我缺少了一些C#魔力?每次看到这样的代码,我都会想到如何实现接口。至于我,我会在接口上使用doSomething()
方法,这样你就可以在所有这些类中实现它。你会:
public void DoSomething(IService service)
{
service.doSomething();
}
一般来说,如果您认为必须在代码中执行类似的操作,这是一个强烈的迹象,表明您的设计有问题。如果您将iSeries设备
接口传递给该方法,那么理想情况下,其目的应该是希望调用该接口上的方法,而不必关心后面的实现
但除此之外,在您的iSeries设备
接口上具有某种Servicetype
属性(理想情况下,这将返回一个枚举值),然后您可以使用switch
语句检查该属性。这当然不会减少必要的逻辑分支数(如果不重构您的体系结构,您将无法减少它),但至少这将显著减少必要的代码量
托马斯如果功能不属于iSeries设备
,则可以使用s和某种类型的映射,或者使用
后者要求您添加一个新方法IService.Visit
,并使用方法Visit(Service1)
和Visit(Service2)
(etc)创建接口IServiceVisitor
例如:
interface IService
{
void Visit(IServiceVisitor visitor);
}
class Service1 : IService
{
void Visit(IServiceVisitor visitor)
{
visitor.Visit(this);
}
}
class Service2 : IService
{
void Visit(IServiceVisitor visitor)
{
visitor.Visit(this);
}
}
interface IServiceVisitor
{
void Visit(Service1 service);
void Visit(Service2 service);
}
class ClassThatDoesStuff : IServiceVisitor
{
{
void Visit(Service1 service)
{
// Service one code
}
void Visit(Service2 service)
{
// Service two code
}
public void DoSomething(IService service)
{
serivce.Visit(this);
}
}
使用多态性,这是一个非常简单的解决方案
class Abstract
{
function something();
}
class A inherit Abstract
{
override something()
}
class B inherit Abstract
{
override something()
}
function foo (Abstract input)
{
input->something()
}
假设您希望根据实际类型执行某些方法,您可以在实例上使用GetMethod,如果该方法存在,则调用它
public void DoSomething(IService service)
{
System.Reflection.MethodInfo method = service.GetType().GetMethod("MySpecialMethod");
if (method != null)
method.Invoke(service, null);
}
这样,您就不必检查类型,只需检查方法是否存在——就像绕着树走一样,所以我希望这种方法是有用的
您还可以使用一系列可能的方法并对它们进行迭代,以这种方式检查每个方法并生成更优雅的代码。正如其他人所说,最简单的解决方案是通过添加的方法在iSeries设备实现内部完成此逻辑
但是,如果此功能确实不属于iSeries设备内部,那么访问者模式将是比大量instanceof检查更好的解决方案
您可以创建一个如下所示的接口
public interface IServiceHandler {
void handleService1(Service1 s);
void handleService2(Service2 s);
// add more methods for every existing subclass of IService
}
使用一个处理DoSomething中当前逻辑的实现,但每个分支都被划分为自己的方法:
public class ServiceHandler : IServiceHandler {
public void handleService1(Service1 s) { ... }
public void handleService2(Service2 s) { ... }
}
iSeries将需要一种添加方法:
void accept(IServiceHandler sh);
这将在特定的实现中实现,如
public class Service1 : IService {
...
public void accept(IServiceHandler sh) { sh.handleService1(this); }
....
}
和其他实现类似
然后可以将原始DoSomething()方法重写为
public void DoSomething(IService service) {
service.accept(new ServiceHandler());
}
这种方法的优点是,您的逻辑将得到更好的隔离,并且由于不再使用c的任何实例,性能也会稍微提高
public class Service1 : IService {
...
public void accept(IServiceHandler sh) { sh.handleService1(this); }
....
}
public void DoSomething(IService service) {
service.accept(new ServiceHandler());
}
class ServiceFactory
{
Dictionary<Type, NewService> serviceCreators;
ServiceFactory()
{
serviceCreators = new Dictionary<Type, NewService>();
serviceCreators.Add(typeof(Task1), delegate { return new SomeService(); });
serviceCreators.Add(typeof(Task2), delegate { return new SomeOtherService(); });
}
public IService CreateService(IServiceTask messageObj)
{
if(serviceCreators.Contains(messageObj.GetType())
{
return serviceCreators[messageObj.GetType()];
}
return new DefaultService();
}
}
delegate IService NewService();