当基类中有更通用的方法时,如何重写基类中的方法
本文关键字:方法 基类 何重写 重写 | 更新日期: 2023-09-27 18:21:07
我有一个名为Base
的基类。这个基类有一个方法定义为:
protected virtual string GetFormattedAttribute(string propertyName, object propertyValue)
propertyValue
定义为:
dynamic propertyValue
因此,不同类型的值被分配给它,并自动调用适当的方法。例如,在DateTime
的同一基类中,我有另一个虚拟方法:
protected virtual string GetFormattedAttribute(string propertyName, DateTime propertyValue)
这非常有效。现在,我有一个dervied类,在其中我定义了相同的方法,它接受List<Contact>
:
protected string GetFormattedAttribute(string propertyName, List<Contact> contacts)
然而,它从未被调用,而是调用了Base
中propertyValue
作为object
的第一个方法(我用派生类对象调用这个方法)。我在派生类方法中尝试了new
和override
关键字,但都不起作用。有什么想法可以让我达到这个结果吗?
这与覆盖无关。您正在创建GetFormattedAttribute
的过载。如果对类型为Base
的变量调用GetFormattedAttribute
,则它不知道派生类中的重载,即使实例实际上是派生类型的。
简单地说:派生类中的重载只会被调用,因为它是在派生类的变量或从派生类派生的类上调用的。因为该方法是受保护的,我假设你在基类中的某个地方调用GetFormattedAttribute
。在这种情况下,您不可能在派生类中使用重载的GetFormattedAttribute
。
实现你想要的结果的一种方法是这样的:
- 在派生类中使用
object
参数重写版本 - 在被覆盖的版本中进行类型检查。如果类型为
List<Contact>
,则调用该重载,否则调用基本实现
类似这样的东西:
class Derived : Base
{
protected override string GetFormattedAttribute(string propertyName,
object propertyValue)
{
var list = propertyValue as List<Contact>;
if(list == null)
return base.GetFormattedAttribute(propertyName, propertyValue);
else
return GetFormattedAttribute(propertyName, list);
}
protected string GetFormattedAttribute(string propertyName,
List<Contact> contacts)
{
// ...
}
}
在我看来,你可以使用泛型来实现你想要的。
所以在基地你会有
protected virtual string GetFormattedAttribute<T>(string propertyName, T propertyValue)
如果所有类型都有某种通用的通用格式,这将非常有用。
在最初的检查中,这似乎很好,但如果您的类型没有一些通用的格式模式(我认为是这样),该怎么办。与其在一个类中实现所有的格式化,我更愿意设计和征服,实现一些与它们正在格式化的类型紧密绑定的小型专用格式化类。此类类将实现通用接口IPropertyFormatter<T>
public interface IPropertyFormatter<T> {
string FormatValue(T value);
}
需要实现此接口的最通用类只是当您为Object.ToString()
获取值时,因此我们将ObjectPropertyFormatter作为IPropertyFormatter 的最通用实现
public class ObjectPropertyFormatter : IPropertyFormatter<Object>
{
public string FormatValue(Object value)
{
//object fallback formatting logic
return value.ToString();
}
}
现在假设某些类型需要特殊处理。然后,我们继续为它们实现特定的属性格式化程序。因此,与其让一个类在所有特定情况下都有大量重载,不如让专用类来处理格式化逻辑。在这个例子中,有一个DateTimePropertyFormatter
和一个BooleanPropertyFormatter
,它们的实现方式如下:
public class DateTimePropertyFormatter : IPropertyFormatter<DateTime>
{
public string FormatValue(DateTime value)
{
//DateTime customised formatting logic
return "<b>" + value.ToString("yyyyMMdd") + "</b>";
}
}
public class BoolPropertyFormatter : IPropertyFormatter<bool>
{
public string FormatValue(bool value)
{
//bool customised formatting logic
if (value)
return "yeaaah";
else
return "nope";
}
}
您可以有更多的类,如List等,每个类都有自己的格式化逻辑,与单一责任原则保持一致
好的,我们有我们的格式化程序,我们如何让所有的格式化程序运行?这就是FormatterResolver
发挥作用的地方。你可以注册格式化程序,他们会
/// <summary>
/// Class responsible for getting the right format resolver for a given type
/// </summary>
public class FormatterResolver
{
private ObjectPropertyFormatter _objectPropertyFormatter;
private Dictionary<Type, object> _registeredFormatters;
public FormatterResolver()
{
_registeredFormatters = new Dictionary<Type, object>();
_objectPropertyFormatter = new ObjectPropertyFormatter();
}
public void RegisterFormatter<T>(IPropertyFormatter<T> formatter)
{
_registeredFormatters.Add(typeof(T), formatter);
}
public Func<string> GetFormatterFunc<T>(T value)
{
object formatter;
if (_registeredFormatters.TryGetValue(typeof(T), out formatter))
{
return () => (formatter as IPropertyFormatter<T>).FormatValue(value);
}
else
return () => ( _objectPropertyFormatter.FormatValue(value));
}
}
您需要在某个地方存储formatResolver的实例并注册所有格式化程序。
public FormatterResolver _formatResolver;
public void RegisterFormatResolvers()
{
_formatResolver = new FormatterResolver();
_formatResolver.RegisterFormatter(new BoolPropertyFormatter());
_formatResolver.RegisterFormatter(new DateTimePropertyFormatter());
//...etc
}
你的方法看起来像这样:
public string GetFormattedAttribute<T>(T propertyValue)
{
return _formatResolver.GetFormatterFunc(propertyValue)();
}
那么,是时候进行测试了,这一切都有效吗?这是一个快速的健全性测试,表明上面的代码可以按预期工作。
[TestMethod]
public void TestFormatResolvers()
{
RegisterFormatResolvers();
Assert.AreEqual("yeaaah", GetFormattedAttribute(true));
Assert.AreEqual("nope", GetFormattedAttribute(false));
Assert.AreEqual("<b>20120120</b>", GetFormattedAttribute(new DateTime(2012, 01, 20)));
Assert.AreEqual("5", GetFormattedAttribute(5));
}
如果您的格式化逻辑也依赖于propertyName,那么您所需要做的就是将接口修改为:
public interface IPropertyFormatter<T> {
string FormatValue(string propertyName, T value);
}
并相应地实现派生类