C# if(obj是thisObj)语句太多

C# if(obj是thisObj)语句太多,c#,C#,我目前有一种方法,试图找出它收到的目标是什么。它知道它在某个接口上,例如iSeries,但我有代码查看它,并试图告诉我它是例如Service1还是Service2。 我目前有很多if(obj是thisObj)风格的语句,要使代码变得漂亮,最好的解决方案是什么 以下是我所拥有的一个样本: public void DoSomething(IService service) { if (service is Service1) {

我目前有一种方法,试图找出它收到的目标是什么。它知道它在某个接口上,例如iSeries,但我有代码查看它,并试图告诉我它是例如Service1还是Service2。 我目前有很多if(obj是thisObj)风格的语句,要使代码变得漂亮,最好的解决方案是什么

以下是我所拥有的一个样本:

    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();