We've covered a lot so far with Part 1, Part 2, Part 3 and Part 4 of this adventure with extension methods.
Looking back at it, there are some nifty features and side effects that might have been overlooked.
With the magic of generic methods and compiler type inference, we are able to get a pretty discoverable and predictable api.
Let's look at the test first:
[Fact]
public void GetProperty()
{
DateTime now = DateTime.Now;
Assert.Equal(now.Day, now.Reflection().GetProperty("Day"));
}
What's in there? Well first we see that there is a Reflection() extension point, and this typed extension point has a GetProperty method. This makes it really EASY to figure out what can be done by reflection.
What should the code look like?
Let's start by the extension point class that will scope all available reflection methods:
public class ReflectionExtensionPoint
{
public T Instance { get; set; }
}
The ReflectionExtensionPoint class is generic so it can hold the type for which we want to use reflection. So we don't have to instantiate it manually all the time, we can create an extension method that will create such an instance
public static class ReflectionExtension
{
public static ReflectionExtensionPoint Reflection(this T instance)
{
return new ReflectionExtensionPoint { Instance = instance };
}
}
Here lies all the magic. Since the method is generic and there are no constraints define, we can use the Reflection extension method on anything. Furthermore, there is no need to specify the generic type argument as it is automatically inferred by the compiler
This allows for a pretty compact syntax as shown here:
[Fact]
public void ReflectionExtensionPoint()
{
DateTime now = DateTime.Now;
ReflectionExtensionPoint<DateTime> extensionPoint = now.Reflection();
Assert.NotNull(extensionPoint);
Assert.Equal(now, extensionPoint.Instance);
}
Now that we have an extension point almost for free that represents a clear and very predictable subset of functionality, we can extend-the-extension-point to add additional behaviors.
public static class ReflectionExtension
{
public static ReflectionExtensionPoint Reflection(this T instance)
{
return new ReflectionExtensionPoint { Instance = instance };
}
public static void SetProperty(
this ReflectionExtensionPoint extensionPoint,
string name,
object value)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(name);
propertyInfo.SetValue(extensionPoint.Instance, value, null);
}
public static object GetProperty(
this ReflectionExtensionPoint extensionPoint,
string name)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(name);
return propertyInfo.GetValue(extensionPoint.Instance, null);
}
}
Of course, extending the generic ReflectionExtensionPoint class, we need to make our extension methods generic as well so that we can propagate the extended type.
By now, unit tests should turn green, and we should be looking for next bits of business value to provide.
