繁体   English   中英

C#当从不同的命名空间中使用两组“相同”类时,如何避免两次写入相同的方法?

[英]C# When consuming two sets of “identical” classes from different namespaces, how do I avoid writing the same method(s) twice?

我有两个名称空间,每个名称空间中有三个类。这两组三个类 - 就我的目的而言 - 在名称和属性上是相同的,但每个集合都存在于它自己的名称空间中。

您可以猜测,此代码是从同一服务的两个实例自动生成的(一个用于生产,另一个用于UAT)。 每个实例可能在同一版本上,也可能不在同一版本上,但我关心的成员总是相同的。

例如:

namespace Domain.Uat //Auto-generated
{
    public class LoginResult { }
    public class ServiceSession { }
    public class Service
    {
        public ServiceSession Session { get; set; }
        public LoginResult Login(string username, string password);
    }
}
namespace Domain.Prod //Auto-generated
{
    public class LoginResult { }
    public class ServiceSession { }
    public class Service
    {
        public ServiceSession Session { get; set; }
        public LoginResult Login(string username, string password);
    }
}

我有一个登录服务的类,并做了很多其他的事情。 我希望能够从UI层选择UAT或Prod,所以我添加了一个名为“isUat”的bool参数给我 - 在这种情况下 - Login()方法。

我想避免编写两个几乎相同的Login()方法。 所以我在考虑这样的事情:

namespace Domain
{
    public class DomainClass
    {
        private object MyService; 
        private object MyLoginResult; 
        private object MySession;

        public void Login(string username, string password, bool isUat)
        {
            //New up the service here:
            if (isUat)
                MyService = new Domain.Uat.Service();
            else
                MyService = new Domain.Prod.Service();

            //Do all the common stuff here
            MyLoginResult = MyService.Login(username, password); 
            MySession = MyService.Session; 
        }

        //(Lots of other methods that use MyService and MySession go here)
    }
}

声明类型对象并向其投射是愚蠢的,但我认为它说明了我的一般方法。 我已经使用部分类和接口(“ILoginResult”,“IServiceSession”,“IService”等)以不同的方式工作,但它感觉很烦人。

是否存在针对此问题的最佳实践模式,还是我写了两个Login()方法?

UPDATE

我上面提到的部分类和接口方法的工作方式如下:

namespace Domain
{
    public interface ILoginResult { }
    public interface IServiceSession { }
    public interface IService
    {
        public IServiceSession Session { get; set; }
        public ILoginResult Login(string username, string password);
    }
}

然后我添加一些代码(不是自动生成的)来扩展自动生成的类:

namespace Domain.Uat //Do the same for Domain.Prod
{
    public partial class LoginResult : Domain.ILoginResult { }
    public partial class ServiceSession : Domain.IServiceSession { }
    public partial class Service : Domain.IService { } //Doesn't work, see below
}

然后我像这样修改我的DomainClass:

namespace Domain
{
    public class DomainClass
    {
        private ILoginResult MyLoginResult;
        private IServiceSession MyServiceSession;
        private IService MyService;

        public void Login(string username, string password, bool isUat)
        {
            //New up the service here
            if (isUat)
                MyService = new Domain.Uat.Service();
            else
                MyService = new Domain.Prod.Service();

            //Common stuff here
            MyLoginResult = MyService.Login(username, password);
            MyServiceSession = MyService.ServiceSession;
        }

        //More members here
    }
}

但是,这不起作用,因为Domain.Uat.Service实际上并不实现Domain.IService。 Domain.IService.ServiceSession获取设置IServiceSession,但Domain.Uat.Service实际上没有名为ServiceSession的IServiceSession属性。 LoginResult也是如此。

所以,现在在我的部分课程中,我不得不像这样实现新的具体成员:

namespace Domain.Uat //Do the same for Domain.Prod
{
    public partial class LoginResult : Domain.ILoginResult { }
    public partial class ServiceSession : Domain.IServiceSession { }
    public partial class Service : Domain.IService
    {
        public Domain.IServiceSession Domain.IService.ServiceSession
        {
            get { return Session; }
            set { Session = (Domain.Uat.ServiceSession)value; }
        }
        public Domain.ILoginResult Domain.IService.Login(string username, string password)
        {
            return Login(username, password);
        }
    }
}

我不喜欢这个,所以我尝试使用泛型来避免具体实现,如下所示:

namespace Domain
{
    public interface ILoginResult { }
    public interface IServiceSession { }
    public interface IService<TLoginResult, TServiceSession>
        where TLoginResult : ILoginResult
        where TServiceSession : IServiceSession
    {
        public TServiceSession Session { get; set; }
        public TLoginResult Login(string username, string password);
    }
}

...导致我的Service类签名发生变化,如下所示:

namespace Domain.Uat //Do the same for Domain.Prod
{
    public partial class LoginResult : Domain.ILoginResult { }
    public partial class ServiceSession : Domain.IServiceSession { }
    public partial class Service : Domain.IService<LoginResult, ServiceSession> { }
}

所以我避免了具体的实现,但是现在当我在DomainClass中使用服务时编译器中断了:

namespace Domain
{
    public class DomainClass
    {
        private IService MyService; 
        private ILoginResult MyLoginResult; 
        private IServiceSession MySession;

        public void Login(string username, string password, bool isUat)
        {
            //New up the service here:
            if (isUat)
                MyService = new Domain.Uat.Service(); //Compiler fail, can't cast
            else
                MyService = new Domain.Prod.Service(); //Compiler fail, can't cast

            //Do all the common stuff here
            MyLoginResult = MyService.Login(username, password); 
            MySession = MyService.Session; 
        }

        //(Lots of other methods that use MyService and MySession go here)
    }
}

我正在挖洞的感觉太深了,所以我退后一步,发布在Stack Overflow上!

PS协方差和逆变法对我的IService接口不起作用,因为一个成员是一个属性(是的,我需要能够在Session上获取和设置)。

我不认为为每个类使用一个接口是不好的。 然后改变为这样。

private ILoginResult MyLoginResult

然后为domainclass创建一个构造函数并传递uat并在构造函数中实例化您的属性。

然后登录方法或任何其他方法将不需要if语句

如果无法控制生成的代码的接口,则可以为从公共接口/抽象类继承的每个服务创建包装器。

public class WrappedUatService : IService {
   private Domain.Uat.Service _service;

   public override ILoginResult Login() { 
       ILoginResult result = new WrappedLoginResult(_service.Login());
       ...
   }
}

public class WrappedProdService : IService {
   private Domain.Prod.Service _service;

   public override ILoginResult Login() { 
       ILoginResult result = new WrappedLoginResult(_service.Login());
       ...
   }
}

这是一些额外的代码,但你不能将它们视为等效的,因为它们碰巧有相同签名的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM