簡體   English   中英

如何在C#中使用派生類型重寫泛型方法

[英]How to override generic method with derived type in c#

我有以下課程:

public interface IService
{
    void ApplyChanges<T>(T parameters) where T : ParamBase;
}

public class ServiceBase : IService
{
    public virtual void ApplyChanges<T>(T parameters) where T : ParamBase
    { }
}
public abstract class Service : ServiceBase
{
    public override void ApplyChanges<T>(T parameters) where T : ParamBase
    {
        Console.WriteLine(parameters.Param2);
        //Apply changes logic here...
    }
}

public abstract class ParamBase
{
    public string Param1 { get; set; }
}

public class ParamA : ParamBase
{
    public string Param2 { get; set; }
}

這是我的測試主要課程:

void Main()
{
  var service = new Service();
  var paramA = new ParamA();
  paramA.Param2 = "Test2";
  service.ApplyChanges<ParamA>(paramA);
}

該實現有什么問題? 如何從Service類中重寫的ApplyChanges方法訪問parameters.Param2

總體思路是,我有一個ServiceBase,並且希望它的派生類能夠將不同的參數類型傳遞給ApplyChanges方法。

我在這里取得了飛躍,但這聽起來像您打算擁有多個“服務”,每個“服務”都具有關聯的參數類型。

如在示例中所做的那樣,將類型參數放在方法上 ,將強制該方法的所有實現都是多態的。 (此術語的技術術語是更高級別的量化 。)

相反,您應該將type參數與服務本身相關聯。 這允許合同的給定實現聲明與之關聯的參數類型。 當您使用它時,我不會理會基類或類型界限。

interface IService<in T>
{
    void ApplyChanges(T param);
}

class Param1
{
    public int X { get; set; }
}
class Service1 : IService<Param1>
{
    public void ApplyChanges(Param1 param)
    {
        param.X = 123;
    }
}

class Param2
{
    public int Y { get; set; }
}
class Service2 : IService<Param2>
{
    public void ApplyChanges(Param2 param)
    {
        param.Y = 456;
    }
}

您不應該對方法重寫施加更嚴格的約束。 覆蓋的方法應擴展可能的輸入參數並減少可能的結果。 否則,它將破壞Liskov替代原則 C#不允許您這樣做。

就是說,如果您真的想要,可以。 但是您不會在調用代碼中收到編譯器警告。 如果您不能更改基類,請使用該解決方案。

public class Service<TParam> : Service where TParam : ParamA
{
    public override void ApplyChanges<T>(T parameters)
    {
        Console.WriteLine((parameters as TParam).Param2);
    }
}

更好的解決方案是向ServiceBaseIService添加類型參數。

public interface IService<TParam>
   where TParam : ParamBase
{
    void ApplyChanges(TParam parameters);
}

public abstract class ServiceBase<TParam> : IService<TParam>
    where TParam : ParamBase
{
    public virtual void ApplyChanges(TParam parameters)
    { }
}
public class Service : ServiceBase<ParamA>
{
    public override void ApplyChanges(ParamA parameters)
    {
        Console.WriteLine(parameters.Param2);
    }
}

實際上,與其替換接口的泛型類型,不如使用“類型防護器”更干凈。 我說的更干凈是因為接口的方法簽名保持一致,實際上,比使用接口更重要的是什么? (顯然,小狗更重要)

在方法本身內,您可以確保類型是所需的一種,例如...

public void Method(ParentRequest req){
if(req is ChildRequest request){
//Do logic here
} else {
    throw new Exception($"request is of type {req.GetType().Name} and must be of type ParentRequest");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM