Strange behavior with extension methods
In a previous post, I already explained what extension methods are and how they work. While doing some tests, I noticed a strange behavior which I will explain in this post.
The order in which .NET searches for the method to be executed is as follow:
- Instance methods of the class
- Static methods within the class
- Extension methods specified for the class
Because the static methods have a higher priority then the extension methods, this can give strange behavior.
In the following sample, the goal is to create an extension method that enables making comparisons on DateTime objects on different levels. The comparison level allows you for example to only compare until the month and not use the day/time while doing the comparison.
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
DateTime d1 = new DateTime(2008, 1, 1);
DateTime d2 = new DateTime(2008, 1, 10);
// Compile time error:
// Member 'object.Equals(object, object)'
// cannot be accessed with an instance
// reference; qualify it with a type
// name instead
d1.Equals(d2, DateComparisonLevel.Month);
}
}
public enum DateComparisonLevel
{
Year,
Month
}
public static class MyUtils
{
public static bool Equals(this DateTime orgDate,
DateTime compDate, DateComparisonLevel level)
{
switch (level)
{
case DateComparisonLevel.Year:
return orgDate.Date.Equals(
new DateTime(
compDate.Year,
orgDate.Month,
orgDate.Day));
case DateComparisonLevel.Month:
return orgDate.Date.Equals(
new DateTime(
compDate.Year,
compDate.Month,
orgDate.Day));
}
return false;
}
}
When trying to compile this code, you will receive a compile time error on the following line:
d1.Equals(d2, DateComparisonLevel.Month);
Error:
Member 'object.Equals(object, object)' cannot be accessed with an instance reference; qualify it with a type name instead.
This is because DateTime derives from System.Object. Since System.Object contains a method with definition
public static bool Equals(object objA, object objB);
the compiler takes this method in case of the extension method. Since the method of the System.Object class is a static method, it can not be called from an instance of an object. The only way to solve this is to rename the Equals method in the code. This way, the Object.Equals method will no longer interfer.
Microsoft considers this as a bug.
3 comments:
Hi Geert,
Thanks for this one! I was wondering though, how come you came to the conclusion stated in the end of the post ("Microsoft considers this as a bug"). Any reference? I couldn't find one...
Thanks,
Amir Simantov
This is the link to the bug report on the connect site.
Strangely, I got this error by simply having the wrong parameter in the method, i.e.
if (sTaskStatus.Equals("Approved", StringComparer.InvariantCultureIgnoreCase))
I used StringComparison instead of StringComparer here.
Post a Comment