我有以下课程:
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类中的覆盖parameters.Param2
方法访问ApplyChanges
?
一般的想法是我有一个ServiceBase,我希望它的派生类能够将不同的参数类型传递给ApplyChanges方法。
答案 0 :(得分:5)
我在这里进行了一次飞跃,但听起来你打算拥有多个&#34;服务&#34;,每个服务都有一个相关的参数类型。
在方法上放置一个类型参数,就像在示例中所做的那样,强制该方法的所有实现都是多态的。 (技术术语是higher-rank quantification。)
相反,您应该将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;
}
}
答案 1 :(得分:4)
您不应对方法覆盖施加更强的约束。重写方法应扩展可能的输入参数,并减少可能的结果。否则它会中断Liskov Substitution Principle。 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);
}
}
答案 2 :(得分:0)
确实,代替替换接口的泛型类型,使用“类型防护器”更为干净。我说的更干净是因为接口的方法签名保持一致,实际上,比使用接口更重要的是什么? (显然,小狗更重要)
在方法本身内,您可以确保类型是所需的类型...
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");
}
}