来自不同命名空间的同名对象的可重用函数代码?

Posted

技术标签:

【中文标题】来自不同命名空间的同名对象的可重用函数代码?【英文标题】:Reusable Function Code For Same-Named Objects From Different Namespaces? 【发布时间】:2017-08-31 10:26:24 【问题描述】:

我正在尝试为两个具有不同名称空间但包含具有相同名称和定义的类的两个 Web 服务编写“包装器”代码。我想编写一些函数代码,可以在每个 Web 服务的包装类中使用,而无需简单地将代码复制到每个 Web 服务中。例如,通过每个对象的名称返回一个对象:

using WebSvc1;
WrapperClassWS1

 // The root class inherits from System.Web.Services.Protocols.SoapHttpClientProtocol
  WebSvc1Root _Root = new WebSvc1Root;

  public MyNonWSobj GetObjectByName(string WhichName)
  
    // Uses GetWS1ObjectByName to retrieve the 'real' object
    //   then turns that into my dumbed down object for use
    //   by calling code that knows nothing about web services
    // Identical code to WrapperClassWS2
    MyNonWSobj myObj = new MyNonWSobj();
    CommonObj returnedObj = this.GetWS1ObjectByName(string WhichName);
    myObj.Name = returnedObj.Name;
    myObj.Revision = returnedObj.Revision;
    myObj.Description = returnedObj.Description;
    return myObj;
  

  private CommonObj GetWSObjectByName(string WhichName)
  
    // Identical code to WrapperClassWS2
    // This function will get an object native to the WebSvc1Root and
    //   the retrieved object will have identical name/definition to
    //   one from WebSvc2Root
    return _Root.getObject(WhichName);
  


using WebSvc2;
WrapperClassWS2

 // The root class inherits from System.Web.Services.Protocols.SoapHttpClientProtocol
  WebSvc2Root _Root = new WebSvc2Root;

  public MyNonWSobj GetObjectByName(string WhichName)
  
    // Uses GetWS2ObjectByName to retrieve the 'real' object
    //   then turns that into my dumbed down object for use
    //   by calling code that knows nothing about web services
    // Identical code to WrapperClassWS2
    MyNonWSobj myObj = new MyNonWSobj();
    CommonObj returnedObj = this.GetWS1ObjectByName(string WhichName);
    myObj.Name = returnedObj.Name;
    myObj.Revision = returnedObj.Revision;
    myObj.Description = returnedObj.Description;
    return myObj;
  

  private CommonObj GetWSObjectByName(string WhichName)
  
    // Identical code to WrapperClassWS1
    // This function will get an object native to the WebSvc2Root and
    //   the retrieved object will have identical name/definition to
    //   one from WebSvc1Root
    return _Root.getObject(WhichName);
  

EDIT2: 从每个 Web 服务返回 CommonObj 类型的函数不需要在两个包装类中以不同的方式命名。由于 _Root 变量在那里初始化,GetWSObjectByName 代码不完全相同。修复了上面的代码。

EDIT1:修正了以下段落中的错误并在上面添加了示例代码。

在我的实际案例中,CommonObj 类的名称相同,并且在两个 Web 服务名称空间中具有相同的定义。获取 Web 服务对象的函数具有相同的名称和定义,但包含“获取 Web 服务对象”函数的类定义具有不同的名称。我真的希望 GetObjectByName 和 GetWSObjectByName 各有一个定义。

我考虑过只使用一个类并为每个 Web 服务的对象定义模块级变量,然后将它们设置为特定于命名空间的对象。这可能会使大部分代码保持通用,但我还没有尝试过。 (我承认这种疯狂的方法植根于 VB6 经验,这是一种相当普遍的做法)。

为了确保我很清楚:我已经为第一个 Web 服务编写了工作代码。通过简单地将所有代码从第一个包装类复制到一个新类,然后更改“使用”语句、类名和表示 Web 服务的模块级变量的类型,我可以为第二个 Web 服务提供相同的工作代码根类。这将解决今天的问题,同时为明天的问题做好准备。

编辑:我的 _Root2 变量的数据类型有误。

编辑:继续寻找清晰...我正在尝试将现有的 Web 服务“包装”在一些代码中,我可以在调用代码/项目时使用这些代码/项目,这些代码/项目将不了解或引用 Web 服务。

【问题讨论】:

你的 wsdl 到 poco 生成器是否生成部分类? 我发现您的问题不清楚,没有一个好的minimal reproducible example 可以清楚地说明您的情况。私有Get...ObjectByName() 方法实际上在做什么?命名空间只是组织类型的一种方式;如果您的每个实现中的代码实际上字面上 相同,我认为没有理由在每个命名空间中都需要一个副本。如果不是字面上相同,实际上存在什么区别? @DanielA.White:对不起,这超出了我的想象! 根据您的示例,我看不出 _Root 字段有两种不同类型的原因,我也看不出 _Root 字段被称为两个不同名称的原因(_Root1 和_Root2)。您无法以这种方式正确共享逻辑。 @KyleB:你是对的 - 我只需要 _Root 两者,而不需要 _Root1 和 _Root2。我猜是被冲昏了头脑。 【参考方案1】:
// An abstract class for shared code
abstract class WrapperClassWS<T> // T enables generics on your abstract class

    private abstract T _Root  get;  // _Root is now of type 'T' (a generic type)

    public MyNonWSobj GetObjectByName(string WhichName)
    
        // ...
    

    private CommonObj GetWSObjectByName(string WhichName)
    
        // ...
    


// Implementation of WS1 wrapper
class WrapperClassWS1 : WrapperClassWS<WebSvc1Root>

    override WebSvc1Root _Root 
     
        get 
         
            return ...; // return root for this namespace
         
            


// Implementation of WS2 wrapper
class WrapperClassWS1 : WrapperClassWS<WebSvc2Root>

    override WebSvc2Root _Root 
     
        get 
         
            return ...; // return root for this namespace
         
            

编辑:我在抽象类中添加了泛型,所以现在实现的类型可以是两个不同的 _Root 类。

如果您想共享逻辑和代码,您将需要保持一些相同的东西,我用泛型编辑了我的示例,因此您可以将 _Root 变量设置为两种不同的类型,但您不能真正调用该变量'_Root1' 和 '_Root2' 如果你想共享逻辑,除非根是根本不同的变量并且将以不同的方式使用。 您可能想研究 SOLID 编程原理。 SOLID 原则可以为您提供一些关于如何有效共享逻辑和分离编程部分的线索,这样您就不会编写以后难以管理的代码。

【讨论】:

在抽象类中,CommonObj 类来自哪个命名空间?另外,我在原始示例中犯了一个严重错误 - 两个 Web 服务中的根类名称不同。 你的回答充满了我不熟悉的东西,考虑到我目前的知识水平,我几乎无法理解,但我还是决定试一试。令我惊讶的是,这似乎有可能奏效。在抽象类的“GetWSObjectByName”函数中,我收到“T”类型不包含 getObject 函数定义的错误(在我的原始帖子中添加了示例代码)。我应该提到我正在使用 .NET 3.5 - 没有充分的理由,而且很容易改变。我还在研究一种使用“动态”的方法,因此可能需要 .NET 4+。【参考方案2】:

您可能需要复制一些代码,但您可以尽量减少重复。我建议创建一个接口来封装每个服务的基本行为。例如:

interface IService 
    MyNonWSobj GetObjectByName(string WhichName)

对于每个服务,您都需要创建一个以某种方式实现此接口的类。

public class ServiceA : IService 

    public MyNonWSobj GetObjectByName(string WhichName)
     
        //Do stuff 
    

    private CommonObj GetWS1ObjectByName(string WhichName)
    
        //Some private implementation stuff 
     

但是,任何需要使用服务并对其进行更复杂操作的代码都可以引用IService,然后它将与任一服务兼容。

public void DoSomethingInterestingWithAService(IService service, string name) 
    var obj = service.GetObjectByName(name);

    DoSomethingCool(obj);

【讨论】:

不幸的是,我的包装类中的大部分代码都属于“私有实现的东西”类别。这就是我不想为了使用这两个 Web 服务而复制的所有复杂代码。

以上是关于来自不同命名空间的同名对象的可重用函数代码?的主要内容,如果未能解决你的问题,请参考以下文章

C++命名空间

函数重载细说

C++通过域作用符引用命名空间

6月14日 空操作 命名空间 视图

为 WCF 服务添加服务引用会生成空的 reference.cs

PHP命名空间