wasimbhalli
wasimbhalli

Reputation: 5242

How to override a method in base class when we have a more general method in base class?

I have a base class called Base. This base class has a method defined as:

protected virtual string GetFormattedAttribute(string propertyName, object propertyValue)

The propertyValue is defined as:

dynamic propertyValue

So different type of values are assigned to it and appropriate methods are called automatically. For example, I have another virtual method in the same base class for DateTime as:

protected virtual string GetFormattedAttribute(string propertyName, DateTime propertyValue)

This works perfectly. Now, I have a dervied class in which I define the same method, which accepts a List<Contact>:

protected string GetFormattedAttribute(string propertyName, List<Contact> contacts)

This, however, is never called and the first method with propertyValue as object in Base is called instead (I'm calling this method with a derived class object). I tried new and override keywords in the derived class method, but that doesn't work. Any ideas how can I achieve this result?

Upvotes: 2

Views: 200

Answers (2)

Anastasiosyal
Anastasiosyal

Reputation: 6626

Seems to me that you could be using generics to achieve what you want.

So In base you would have

protected virtual string GetFormattedAttribute<T>(string propertyName, T propertyValue)

This would be useful if all types have some sort of common generic formatting.

That seems nice on initial inspection, but what if your types do not have some generic formatting pattern (which I assume to be the case). Rather than implementing all the formatting in one single class, I would much rather devide and conquer, implementing some small dedicated formatted classes tightly bound to the type they are formatting. Such classes would implement the generic interface IPropertyFormatter<T>

    public interface IPropertyFormatter<T> {
        string FormatValue(T value);
    } 

The most generic class that would need to implement this interface is simply when you do for the Object.ToString() to get the value, hence we have the ObjectPropertyFormatter as the most generic implementation of IPropertyFormatter

    public class ObjectPropertyFormatter :  IPropertyFormatter<Object>
    {
        public string FormatValue(Object value)
        {
            //object fallback formatting logic 
            return  value.ToString();
        }
    }

Now suppose some types need special handling. Then we go ahead and implement specific property formatters for them. So rather than having one class with tons of overloads for all the specific cases, you have dedicated classes that handled the formatting logic. In this example there is a DateTimePropertyFormatter and a BooleanPropertyFormatter and they would be implemented like so:

    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";
        }
    }

You could have many more classes such as List and so on, each with their own formatting logic keeping inline with the single responsibility principle

Right, so we have our formatters, how do we get all our formatters to run? This is where the FormatterResolver comes into play. You can register formatters and they will

    /// <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));

        }
    }

You would need somewhere to store an instance of a formatResolver and register all the formatters.

    public FormatterResolver _formatResolver;

    public void RegisterFormatResolvers()
    {
        _formatResolver = new FormatterResolver();
        _formatResolver.RegisterFormatter(new BoolPropertyFormatter());
        _formatResolver.RegisterFormatter(new DateTimePropertyFormatter());
        //...etc

    }

Your method would then look something like this:

    public string GetFormattedAttribute<T>(T propertyValue)
    {
        return _formatResolver.GetFormatterFunc(propertyValue)();
    }

So, time to put it to the test, does this all work? This is a quick sanity test that shows that the above code works as expected.

    [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));
    }

If your formatting logic is also dependent on propertyName then all you would need to do is amend the interface to:

    public interface IPropertyFormatter<T> {
        string FormatValue(string propertyName, T value);
    } 

and implement the descendent classes accordingly

Upvotes: 1

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174477

This has nothing to do with an override. You are creating an overload of GetFormattedAttribute. If you call GetFormattedAttribute on a variable of type Base it doesn't know about the overload in the derived class, even if the instance in fact is of the derived type.

To put it simply: Your overload in the derived class will only be called, of it is being called on a variable of the derived class or a class that derives from it. Because the method is protected, I assume that you call GetFormattedAttribute somewhere in your base class. In that scenario, it is impossible for you to use the overloaded GetFormattedAttribute in the derived class.

One way to achieve the result you are looking for would be something like this:

  1. override the version with the object parameter in your derived class
  2. put a type check in that overriden version. If the type is List<Contact> call that overload, otherwise call the base implementation

Something like this:

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

Upvotes: 3

Related Questions