簡體   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