繁体   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