[英]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);
}
}
更好的解決方案是向ServiceBase
和IService
添加類型參數。
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.