当我们在基类中有一个更通用的方法时,如何覆盖基类中的方法?

时间:2012-01-20 14:49:35

标签: c# override

我有一个名为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)

然而,这从未被调用,并且propertyValueobjectBase的第一个方法被调用(我正在使用派生类对象调用此方法)。我在派生类方法中尝试了newoverride个关键字,但这不起作用。任何想法如何才能实现这一结果?

2 个答案:

答案 0 :(得分:3)

这与覆盖无关。您正在创建GetFormattedAttribute重载。如果对GetFormattedAttribute类型的变量调用Base,它就不知道派生类中的重载,即使实例实际上是派生类型。

简单地说:派生类中的重载只会被调用,它是在派生类的变量或从派生类派生的类上调用的。因为该方法是受保护的,所以我假设你在基类的某个地方调用GetFormattedAttribute。在这种情况下,您无法在派生类中使用重载的GetFormattedAttribute

实现您正在寻找的结果的一种方法是:

  1. 使用派生类
  2. 中的object参数覆盖该版本
  3. 在该覆盖版本中进行类型检查。如果类型为List<Contact>,则调用该重载,否则调用基本实现
  4. 这样的事情:

    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)
        {
            // ...
        }
    }
    

答案 1 :(得分:1)

在我看来,您可以使用泛型来实现您想要的效果。

所以在基地你会有

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等,每个类都有自己的格式逻辑,与single responsibility principle

保持内联

是的,所以我们有格式化程序,我们如何让所有格式化程序运行?这是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);
    } 

并相应地实施后代类