XmlSerializer and automatic collection properties

August 7, 2009 at 2:09 PMAndre Loker

I noticed an interesting detail in the way XmlSerializer handles collection properties. FxCop rule CA2227 suggest to make collection properties read-only, because XmlSerializer is treating collections differently as described here (scroll down to the “Note” box under “Overriding Default Serialization”). When I tried to serialize the following class, however, I got an error during serialization:

   1: public class SomeClass
   2: {
   3:   public SomeClass()
   4:   {
   5:     CollectionProperty = new List<int>();
   6:   }
   7:  
   8:   public List<int> CollectionProperty { get; private set; }
   9: }

The error was something like:

System.InvalidOperationException: Unable to generate a temporary class (result=1).

error CS0200: Property or indexer 'SomeClass.CollectionProperty' cannot be assigned to — it is read only.

Erm, right, I made it read-only because FxCop suggested it, so what’s wrong here? The answer is that “making the collection property read-only” should be read as “don’t provide a setter of any visibility”, because technically a property with a private setter is still writable, albeit from within the class only, leading to the runtime error as described above. FxCop on the other hand will stop complaining as soon as the setter is made private. 

As soon as I changed the automatic property to a property with backing field without a setter the application ran fine:

   1: public class SomeClass
   2: {
   3:   private readonly List<int> collectionProperty;
   4:  
   5:   public SomeClass()
   6:   {
   7:     collectionProperty = new List<int>();
   8:   }
   9:  
  10:   public List<int> CollectionProperty
  11:   {
  12:     get { return collectionProperty; }
  13:   }
  14: }

Posted in: C#

Tags: , ,

Extension methods: If you have a shiny new hammer

March 20, 2009 at 10:40 AMAndre Loker

If you have a shiny new hammer, every problem looks like a nail they say. Although C# 3.0 extension methods are not that new anymore, this saying still applies. I ran across the announcement of the Generic Extension Methods Project. While I think a repository of useful extension methods sounds like a cool idea, one piece of code in that said announcement made me smile slightly:

   1: // IsNotNull is an extension method
   2: if(row.IsNotNull())
   3: {
   4:     row["First Column"] = "some value";
   5: }

Call me old fashioned, but I personally prefer the good old null-check a lot:

   1: // Pure and simple
   2: if(row != null)
   3: {
   4:     row["First Column"] = "some value";
   5: }

something != null  is an expression every developer understands. If I don’t know about extension methods or don’t know in particular that IsNotNull() is an extension method, I’d ask myself: “What does a method IsNotNull() do? Is nullness meant to be something different here? It has to, because calling a method on a null-variable would cause a NullReferenceException, wouldn’t it?”.

One inherent semantic of C# is that if you call a method on a null reference, it will crash. IsNotNull() is therefore completely counterintuitive. Either you force the reader to consider the possibility that the method might be an extension method and therefore you could call that method on null. Or you help those readers by preceding all usages of IsNotNull() with comments like “Note, this is an extension method”. Yuck!

But maybe this IsNotNull() implementation does a bit more for DataTableRows than just checking them to be not null. If it does, it’s name is misleading.

So you see: using IsNotNull() adds nothing but confusion to the code.

My personal recommendations regarding extension methods:

  • Don’t use them just because you can.
    • The ultimate goal should be to write simple, readable, comprehensible code. If an extension method helps – use it. If it doesn’t or is even counterproductive – don’t!
  • If there is a simpler concept built into the language, prefer that over extension methods. Some (partly far-fetched) examples:
    • prefer something != null over something.IsNotNull()
    • prefer if(something)… over if(something.IsTrue())…
    • prefer x = a + 1 over x = a.PlusOne()

A brief review

That being said, here’s a brief review of the extension methods that are found in the project as of now:

CollectionExtensions

FirstItem returns the first item of a list or array or null if there is no such item. Isn’t that what FirstOrDefault already does?

ReflectionExtensions

CreateInstance – which extends Type - comes in two flavours:

The first one tries to create an instance using the default constructor:

   1: public static T CreateInstance<T>(this System.Type type) where T : new()

Although the documentation says that you could use it like “typeof(MyObject).CreateInstance()” this is not true – you need to provide something for T. Not only do you need to provide the type twice (as the extended object and as T), you also end up with possible constructs like:

   1: typeof(string).CreateInstance<Version>();

This happily creates an instance of Version. What’s the use of extending Type then? Just use Activator – it’s simple and works:

   1: Activator.CreateInstance<Version>()

The other overload of CreateInstance additionally allows for constructor arguments being passed. What’s been said above still counts, typeof(string).CreateInstance<Version>(1,2,3,4) is awkward.

Just as a side note: what’s the use of a generic object creation method anyway? The documentation of Activator.CreateInstance<T> puts it nicely:

In general, there is no use for the CreateInstance in application code, because the type must be known at compile time. If the type is known at compile time, normal instantiation syntax can be used.

That is: if somewhere in the code I am able to say Activator.CreateInstance<Foo>() – why don’t I just say new Foo() in the first place? What I’d find more useful is something like this:

   1: public static T InstantiateAs<T>(this Type type) {
   2:   return (T) type.Instantiate();
   3: }
   4:  
   5: public static object Instantiate(this Type type) {
   6:   return Activator.CreateInstance(type);
   7: }

So you could say:

   1: Type type = ReadSomeTypeFromConfig(); // returns e.g. typeof(ServiceImpl)
   2: IService myService = type.InstantiateAs<IService>();

And likewise add overloads that accept constructor arguments.

ValidationExtensions

This class contains extension methods such as IsNull or IsNotNull – which I don’t like at all as explained above.

Additionally, you’ll find assertion methods like

   1: public static void AssertParameterNotNull(this object value, 
   2:                                           string message, 
   3:                                           string name)

It’s probably a matter of taste whether you like it or not. Again, I prefer a more explicit way. I prefer not to allow method calls on possible null-values and go with:

   1: Assert.ArgumentIsNotNull(theArgument, "theArgument", "Boy, that arg can't be null!")

Then we have AssertEquals which is supposed to be used like this:

   1: someValue.AssertEquals<MyException>(someOtherValue, "Some message");

That is, MyException is thrown if someValue does not equal someOtherValue. I can’t help it, it feels weird.

Next one:

   1: public static bool IsEmpty(this string value)
   2: public static bool IsNotEmpty(this string value)

Looks reasonable, doesn’t it? The problem with these methods is that their names are very misleading:

   1: /// <summary>
   2: /// Tests if the string is empty.
   3: /// </summary>
   4: /// <param name="value">The string to test.</param>
   5: /// <returns>True if the string is empty.</returns>
   6: public static bool IsEmpty(this string value)
   7: {
   8:     return value.Trim().Length == 0;
   9: }
  10:  
  11: /// <summary>
  12: /// Tests if the string is not empty.
  13: /// </summary>
  14: /// <param name="value">The string to test.</param>
  15: /// <returns>True if the string is not empty.</returns>
  16: public static bool IsNotEmpty(this string value)
  17: {
  18:     return value.Trim().Length > 0;
  19: }

According to those methods, “    “.IsEmpty() == true. Which is confusing because string.IsNullOrEmpty(“    “) returns false. I’d heavily suggest to rename those methods and be clear about the behaviour in the documentation.

Finally, there are a bunch of methods called IsEmpty and IsNotEmpty that work on different collection types (why aren’t they placed in the CollectionExtensions class?). While I find those methods useful there is an extreme amount of duplication. All those methods can be covered by these to little guys:

   1: public static bool IsEmpty<T>(this T collection) where T : ICollection {
   2:   return collection.Count == 0;
   3: }
   4:  
   5: public static bool IsNotEmpty<T>(this T collection) where T : ICollection {
   6:   return !collection.IsEmpty();
   7: }

Because all of the types handled in the library (ICollection, ICollection<T>, IList, IList<T>, IDictionary, IDictionary<K, T>, Array) inherit ICollection. Why did I make IsEmpty generic instead of just passing an ICollection? It’s just a little trick: if for whatever reason you have a value type that implements ICollection invoking IsEmpty(ICollection) on it would cause it to be boxed to treat it as an ICollection. By making IsEmpty generic with a constrained this boxing will not occur. OK, it’s not likely to happen, but I prefer this style. It explicitly says: “It operates on everything that can behave like an ICollection” rather than “It operates on an ICollection”. Sometimes it’s in the details.

Posted in: C# | Patterns

Tags: ,

Ruby’s send in C#

March 18, 2009 at 1:42 PMAndre Loker

In the comment’s of a blog post some developer coming from Ruby wishes C# to have something similar to Ruby’s send functionality, i.e. being able to dynamically invoke a method on an object like this:

   1: theObject.Send("Foo", 1, 2, 3);

This would call the method Foo on theObject with the arguments 1, 2 and 3.

Of course we can use reflection to invoke a method, but it takes same amount of code to do that. The proposed way (just calling a Send method on an arbitrary) looks very compact. How can we achieve that in C#? Of course, through extension methods! So I took the time to implement the Send functionality in C#:

Source code:

   1: #region Copyright (c) 2009, Andre Loker <mail@andreloker.de>
   2: // Permission to use, copy, modify, and/or distribute this software for any
   3: // purpose with or without fee is hereby granted, provided that the above
   4: // copyright notice and this permission notice appear in all copies.
   5: //
   6: // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   7: // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   8: // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   9: // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  10: // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  11: // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  12: // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  13: #endregion
  14:  
  15: using System;
  16: using System.Collections.Generic;
  17: using System.Linq;
  18: using System.Reflection;
  19:  
  20: public static class ObjectSendExtensions {
  21:   /// <summary>
  22:   /// Invokes a method on the <paramref name="target"/>
  23:   /// </summary>
  24:   /// <param name="target">The target, must not be <c>null</c></param>
  25:   /// <param name="methodName">Name of the method, must not be <c>null</c></param>
  26:   /// <param name="args">The arguments passed to the method.</param>
  27:   /// <remarks>
  28:   /// If the target type contains multiple overload of the given <paramref name="methodName"/>
  29:   /// <see cref="Send"/> tries to find the best match.
  30:   /// </remarks>
  31:   /// <exception cref="ArgumentException">
  32:   /// No method with the given <paramref name="methodName"/> was found or the invocation
  33:   /// is ambiguous, ie. multiple methods match.
  34:   /// </exception>
  35:   public static object Send(this object target, string methodName, params object[] args) {
  36:     return Send<object>(target, methodName, args);
  37:   }
  38:  
  39:   /// <summary>
  40:   /// Invokes a method on the <paramref name="target"/>
  41:   /// </summary>
  42:   /// <param name="target">The target, must not be <c>null</c></param>
  43:   /// <param name="methodName">Name of the method, must not be <c>null</c></param>
  44:   /// <param name="args">The arguments passed to the method.</param>
  45:   /// <remarks>
  46:   /// If the target type contains multiple overload of the given <paramref name="methodName"/>
  47:   /// <see cref="Send"/> tries to find the best match.
  48:   /// </remarks>
  49:   /// <exception cref="ArgumentException">
  50:   /// No method with the given <paramref name="methodName"/> was found or the invocation
  51:   /// is ambiguous, ie. multiple methods match.
  52:   /// </exception>
  53:   /// <returns>The value returned from the invoked method cast to a 
  54:   /// <typeparamref name="T"/>
  55:   /// </returns>
  56:   public static T Send<T>(this object target, string methodName, params object[] args) {
  57:     if(target == null) {
  58:       throw new ArgumentNullException("target");
  59:     }
  60:  
  61:     if(methodName == null) {
  62:       throw new ArgumentNullException("methodName");
  63:     }
  64:  
  65:     var type = target.GetType();
  66:     var methods = GetMethodCandidates(methodName, type);
  67:     var methodToInvoke = FindBestFittingMethod(methods, args);
  68:     return InvokeFunction<T>(target, methodToInvoke, args);
  69:   }
  70:  
  71:   static IEnumerable<MethodInfo> GetMethodCandidates(string methodName, Type type) {
  72:     return from method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
  73:            where method.Name == methodName
  74:            select method;
  75:   }
  76:  
  77:   static MethodInfo FindBestFittingMethod(IEnumerable<MethodInfo> methods, object[] args) {
  78:     var highestScore = -1;
  79:     var matchingMethodCount = 0;
  80:     MethodInfo selectedMethod = null;
  81:  
  82:     foreach(var method in methods) {
  83:       var methodScore = RateMethodMatch(method.GetParameters(), args);
  84:       if(methodScore > highestScore) {
  85:         matchingMethodCount = 1;
  86:         highestScore = methodScore;
  87:         selectedMethod = method;
  88:       } else if(methodScore == highestScore) {
  89:         // count the number of matches, match count > 1 => ambiguous call
  90:         matchingMethodCount++;
  91:       }
  92:     }
  93:  
  94:     if(matchingMethodCount > 1) {
  95:       throw new ArgumentException("Ambiguous method invocation");
  96:     }
  97:     return selectedMethod;
  98:   }
  99:  
 100:  
 101:   /// <returns>0 if the arguments don't match the parameters; a score &gt; 0 otherwise.</returns>
 102:   static int RateMethodMatch(ParameterInfo[] parameters, object[] args) {
 103:     var argsLength = args != null ? args.Length : 0;
 104:     if(parameters.Length == argsLength) {
 105:       return argsLength == 0 ? 1 : RateParameterMatches(parameters, args);
 106:     }
 107:     return 0;
 108:   }
 109:  
 110:   static int RateParameterMatches(ParameterInfo[] parameters, object[] args) {
 111:     var score = 0;
 112:     for(var i = 0; i < args.Length; ++i) {
 113:       var typeMatchScore = RateParameterMatch(parameters[i], args[i]);
 114:       if(typeMatchScore == 0) {
 115:         return 0;
 116:       }
 117:       score += typeMatchScore;
 118:     }
 119:     return score;
 120:   }
 121:  
 122:  
 123:   static int RateParameterMatch(ParameterInfo parameter, object arg) {
 124:     var parameterType = parameter.ParameterType;
 125:     return arg == null ? RateNullArgument(parameterType) : RateNonNullArgument(arg, parameterType);
 126:   }
 127:  
 128:   static int RateNullArgument(Type parameterType) {
 129:     return CanBeNull(parameterType) ? 1 : 0;
 130:   }
 131:  
 132:   static bool CanBeNull(Type type) {
 133:     return !type.IsValueType || IsNullableType(type);
 134:   }
 135:  
 136:   static bool IsNullableType(Type type) {
 137:     return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
 138:   }
 139:  
 140:   static int RateNonNullArgument(object arg, Type parameterType) {
 141:     var argType = arg.GetType();
 142:     if(argType == parameterType) {
 143:       // perfect match!
 144:       return 2;
 145:     }
 146:     if(parameterType.IsAssignableFrom(argType)) {
 147:       // at least convertible to parameter type
 148:       return 1;
 149:     }
 150:     return 0;
 151:   }
 152:  
 153:   static T InvokeFunction<T>(object target, MethodInfo method, object[] args) {
 154:     if(method == null) {
 155:       throw new ArgumentException("Method not found");
 156:     }
 157:     return (T) method.Invoke(target, args);
 158:   }
 159: }

Tests (MbUnit 3):

   1: #region Copyright (c) 2009, Andre Loker <mail@andreloker.de>
   2: // Permission to use, copy, modify, and/or distribute this software for any
   3: // purpose with or without fee is hereby granted, provided that the above
   4: // copyright notice and this permission notice appear in all copies.
   5: //
   6: // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   7: // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   8: // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   9: // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  10: // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  11: // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  12: // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  13: #endregion
  14:  
  15: using System;
  16: using MbUnit.Framework;
  17: using Rhino.Mocks;
  18:  
  19: [TestFixture]
  20: public class ObjectSendExtensionTests {
  21:   [Test]
  22:   public void FailsIfTargetIsNull() {
  23:     const string x = null;
  24:     Assert.Throws<ArgumentNullException>(() => x.Send("ToString"));
  25:   }
  26:  
  27:   [Test]
  28:   public void FailsIfMethodNameIsNull() {
  29:     Assert.Throws<ArgumentNullException>(() => 123.Send(null));
  30:   }
  31:  
  32:   [Test]
  33:   public void CanInvokeUniqueMethodWithoutArgs() {
  34:     var mock = MockRepository.GenerateMock<IUniqueMethodWithoutArgs>();
  35:     mock.Send("Foo");
  36:     mock.AssertWasCalled(x => x.Foo());
  37:   }
  38:  
  39:   [Test]
  40:   public void CanDistinguishMethodsByParameterCount_FirstMethod() {
  41:     var mock = MockRepository.GenerateMock<ISimpleOverload>();
  42:     mock.Send("Foo");
  43:     mock.AssertWasCalled(x => x.Foo());
  44:     mock.AssertWasNotCalled(x => x.Foo(Arg<int>.Is.Anything));
  45:   }
  46:  
  47:   [Test]
  48:   public void CanDistinguishMethodsByParameterCount_SecondMethod() {
  49:     var mock = MockRepository.GenerateMock<ISimpleOverload>();
  50:     mock.Send("Foo", 42);
  51:     mock.AssertWasCalled(x => x.Foo(Arg.Is(42)));
  52:     mock.AssertWasNotCalled(x => x.Foo());
  53:   }
  54:  
  55:   [Test]
  56:   public void CanPassArgumentsToMethod() {
  57:     var mock = MockRepository.GenerateMock<ISimpleArguments>();
  58:     mock.Send("Foo", 4, "bar");
  59:     mock.AssertWasCalled(x => x.Foo(Arg.Is(4), Arg.Is("bar")));
  60:   }
  61:  
  62:   [Test]
  63:   public void CanDoSimpleParameterResolution_StringOverload() {
  64:     var mock = MockRepository.GenerateMock<IParameterResolution>();
  65:     var arg = "bar";
  66:     mock.Send("Foo", arg);
  67:     mock.AssertWasCalled(x => x.Foo(Arg.Is(arg)));
  68:     mock.AssertWasNotCalled(x => x.Foo(Arg<Version>.Is.Anything));
  69:     mock.AssertWasNotCalled(x => x.Foo(Arg<int>.Is.Anything));
  70:   }
  71:  
  72:   [Test]
  73:   public void CanDoSimpleParameterResolution_VersionOverload() {
  74:     var mock = MockRepository.GenerateMock<IParameterResolution>();
  75:     var arg = new Version(1, 2, 3);
  76:     mock.Send("Foo", arg);
  77:     mock.AssertWasCalled(x => x.Foo(Arg.Is(arg)));
  78:     mock.AssertWasNotCalled(x => x.Foo(Arg<string>.Is.Anything));
  79:     mock.AssertWasNotCalled(x => x.Foo(Arg<int>.Is.Anything));
  80:   }
  81:  
  82:   [Test]
  83:   public void CanDoSimpleParameterResolution_IntOverload() {
  84:     var mock = MockRepository.GenerateMock<IParameterResolution>();
  85:     var arg = 42;
  86:     mock.Send("Foo", arg);
  87:     mock.AssertWasCalled(x => x.Foo(Arg.Is(arg)));
  88:     mock.AssertWasNotCalled(x => x.Foo(Arg<string>.Is.Anything));
  89:     mock.AssertWasNotCalled(x => x.Foo(Arg<Version>.Is.Anything));
  90:   }
  91:  
  92:   [Test]
  93:   public void CanHandleNullableArguments() {
  94:     var mock = MockRepository.GenerateMock<INullableParameters>();
  95:     int? arg = 42;
  96:     mock.Send("Foo", arg);
  97:     mock.AssertWasCalled(x => x.Foo(Arg.Is(arg)));
  98:     mock.AssertWasNotCalled(x => x.Foo(Arg<float>.Is.Anything));
  99:   }
 100:  
 101:   [Test]
 102:   public void CanHandleNullableArgumentsWithNullValue() {
 103:     var mock = MockRepository.GenerateMock<INullableParameters>();
 104:     int? arg = null;
 105:     mock.Send("Foo", arg);
 106:     mock.AssertWasCalled(x => x.Foo(Arg.Is(arg)));
 107:     mock.AssertWasNotCalled(x => x.Foo(Arg<float>.Is.Anything));
 108:   }
 109:  
 110:   [Test, Description("Although not desired this behaviour is expected")]
 111:   public void SuffersFromNullableBoxingBehaviour() {
 112:     var mock = MockRepository.GenerateMock<INullableParametersBoxingIssue>();
 113:     int? arg = 42;
 114:     mock.Send("Foo", arg);
 115:     mock.AssertWasCalled(x => x.Foo(Arg<int>.Is.Equal(42)));
 116:     mock.AssertWasNotCalled(x => x.Foo(Arg<int?>.Is.Anything));
 117:   }
 118:  
 119:   [Test]
 120:   public void TriesToMatchTypesAsGoodAsPossible() {
 121:     var mock = MockRepository.GenerateMock<ISelectPolymorphic>();
 122:     var item = new DerivedClass();
 123:     mock.Send("Foo", item);
 124:     mock.AssertWasCalled(x => x.Foo(Arg<DerivedClass>.Is.Same(item)));
 125:     mock.AssertWasNotCalled(x => x.Foo(Arg<BaseClass>.Is.Anything));
 126:   }
 127:  
 128:   [Test]
 129:   public void TriesToMatchTypesAsGoodAsPossible2() {
 130:     var mock = MockRepository.GenerateMock<ISelectPolymorphic2>();
 131:     var item = new DerivedClass();
 132:     mock.Send("Foo", null, item);
 133:     mock.AssertWasCalled(x => x.Foo(Arg<BaseClass>.Is.Null, Arg<DerivedClass>.Is.Same(item)));
 134:     mock.AssertWasNotCalled(x => x.Foo(Arg<BaseClass>.Is.Anything, Arg<BaseClass>.Is.Anything));
 135:   }
 136:  
 137:   [Test]
 138:   public void CanCauseAmbiguousInvocation() {
 139:     var mock = MockRepository.GenerateMock<ISelectPolymorphic>();
 140:  
 141:     var exception = Assert.Throws<ArgumentException>(() => mock.Send("Foo", new object[] { null }));
 142:     Assert.AreEqual("Ambiguous method invocation", exception.Message);
 143:   }
 144:  
 145:   [Test]
 146:   public void CanHandleNullArrayAsArguments() {
 147:     var mock = MockRepository.GenerateMock<IUniqueMethodWithoutArgs>();
 148:     mock.Send("Foo", default(object[]));
 149:     mock.AssertWasCalled(x => x.Foo());
 150:   }
 151:  
 152:   [Test]
 153:   public void ReturnsReturnValue() {
 154:     var stub = MockRepository.GenerateStub<IReturnValue>();
 155:     stub.Stub(x => x.IntFoo()).Return(123);
 156:     stub.Stub(x => x.StringFoo()).Return("bar");
 157:  
 158:     var intResult = stub.Send("IntFoo");
 159:     var stringResult = stub.Send("StringFoo");
 160:  
 161:     Assert.AreEqual(123, intResult);
 162:     Assert.AreEqual("bar", stringResult);
 163:   }
 164:  
 165:   [Test]
 166:   public void ReturnsCastReturnValue() {
 167:     var stub = MockRepository.GenerateStub<IReturnValue>();
 168:     stub.Stub(x => x.IntFoo()).Return(123);
 169:     stub.Stub(x => x.StringFoo()).Return("bar");
 170:  
 171:     int intResult = stub.Send<int>("IntFoo");
 172:     string stringResult = stub.Send<string>("StringFoo");
 173:  
 174:     Assert.AreEqual(123, intResult);
 175:     Assert.AreEqual("bar", stringResult);
 176:   }
 177:  
 178:   public interface IUniqueMethodWithoutArgs {
 179:     void Foo();
 180:   }
 181:  
 182:   public interface ISimpleOverload {
 183:     void Foo();
 184:     void Foo(int x);
 185:   }
 186:  
 187:   public interface ISimpleArguments {
 188:     void Foo(int x, string y);
 189:   }
 190:  
 191:   public interface IParameterResolution {
 192:     void Foo(string x);
 193:     void Foo(Version x);
 194:     void Foo(int x);
 195:   }
 196:  
 197:   public interface INullableParameters {
 198:     void Foo(float a);
 199:     void Foo(int? a);
 200:   }
 201:  
 202:   public interface INullableParametersBoxingIssue {
 203:     void Foo(int a);
 204:     void Foo(int? a);
 205:   }
 206:  
 207:   public interface ISelectPolymorphic {
 208:     void Foo(BaseClass arg);
 209:     void Foo(DerivedClass arg);
 210:   }
 211:  
 212:   public interface ISelectPolymorphic2 {
 213:     void Foo(BaseClass arg, BaseClass arg2);
 214:     void Foo(BaseClass arg, DerivedClass arg2);
 215:   }
 216:  
 217:   public interface IReturnValue {
 218:     int IntFoo();
 219:     string StringFoo();
 220:   }
 221:  
 222:   public class BaseClass {
 223:   }
 224:  
 225:   public class DerivedClass : BaseClass {
 226:   }
 227: }

Usage:

   1: public static void Main(string[] args) {
   2:   object o = new Random();
   3:   UseObject(o);
   4: }
   5:  
   6: static void UseObject(object o) {
   7:   Console.WriteLine("Next: {0}",          o.Send("Next"));
   8:   Console.WriteLine("Ranged next: {0}",   o.Send("Next", 45));
   9:   Console.WriteLine("Ranged next 2: {0}", o.Send("Next", 10, 20));
  10: }

Some facts about the implementation:

  • It intentionally only supports public instance methods
  • It supports overloaded functions and tries to match the method to invoke depending on the arguments being passed
  • It won’t invoke Foo(SomeValueType?) if Foo(SomeValueType) is present due to the way nullable values are boxed

If you find this useful, feel free to use it in your projects. The code is ISC licensed.

ObjectSendExtensions.cs (5.87 kb)

ObjectSendExtensionTests.cs (7.24 kb)

Posted in: C#

Tags: ,

Boxing nullables

March 18, 2009 at 12:36 PMAndre Loker

When value types are boxed, the boxed version has the same type as the type being boxed.

For example, boxing an int creates an object of type int:

   1: int number = 42;
   2: object boxedInt = number;
   3: Assert.IsTrue(boxedInt.GetType() == typeof(int));

Likewise for structures such as Guid:

   1: Guid id = Guid.NewGuid();
   2: object boxedGuid = id;
   3: Assert.IsTrue(boxedGuid.GetType() == typeof(Guid));

So far so good. But what happens if you box a nullable value type?

   1: int? nullableNumber = 42;
   2: object boxedNullable = nullableNumber;
   3: Assert.IsTrue(boxedNullable.GetType() == typeof(int?));

Maybe you expected this (I didn’t), but this fails. If you test boxedNullable.GetType() you will get “System.Int32”.

It seems that nullable values (which are nothing more than instances of the Nullable<T> structure) are boxed slightly different than normal value types:

  • if the nullable has no value (HasValue is false), the nullable is boxed as null
  • if the nullable has a value, that value is boxed

This way boxing is slightly more efficient because Nullable<T> contains two fields (“boolean hasValue” and “T value”) and the fact that either null or the boxed value is returned during boxing already encodes the value of hasValue. Thus, this seems to be a smart choice. And why would we want to bother in the first place?

Let’s say you have a method like this:

   1: public void DoSomething(params object[] objects) {
   2:   foreach(var item in objects) {
   3:     // do something depending on the type of item
   4:   }
   5: }

And you invoke it with the three objects that we created in the examples above:

   1: DoSomething(number, id, nullableNumber);

Then DoSomething has no chance of distinguishing between the type of the first and the third argument – both will be System.Int32 - which might lead to undesired or unexpected behaviour.

Conclusion

If your code makes decisions based on the type of a boxed value be aware that nullable values are boxed slightly different: they lose their “Nullable-ness” and become either null or the boxed version of the value that they hold.

Posted in: C#

Tags: ,

Simple AOP: integrating interceptors into Windsor

February 20, 2009 at 3:47 PMAndre Loker

Aspect oriented programming (AOP) allows us to keep implement different concerns in isolation. In this article series I’ll describe ways to make use of AOP without much hassle. In the previous article of this serious we learned how to intercept method invocations using DynamicProxy2 and IInterceptors. However, we had to create the proxy instances manually. If you use Castle Windsor you can let the IoC container create the proxies and inject the interceptors.

I assume that you have used Castle Windsor or a different IoC container before. If not, check why you should use dependency injection.

Luckily Windsor integration of IInterceptors is a snap. In fact, you don’t have to add anything, it’s already been built in, because it has proven to be very useful. Because Windsor controls the instantiation of the registered components it was a logical consequence to add optional proxy creation and interface injection into that process. The Castle people are know what they do!

Basically, Windsor offers three ways to define interceptors that you want it to inject into components, ranging from rather static to fully dynamic.

Static injection with attributes

If all you want is the separation of concerns that injectors offer you and know which classes those aspects need to be applied to you can simply use the InterceptorAttribute.

Let’s start with a simple service interface and its implementation:

   1: public interface IService {
   2:     void DoSomething();
   3: }
   4:  
   5: public class Service : IService {
   6:     public void DoSomething() {
   7:         Console.WriteLine("Doing something");
   8:         throw new InvalidOperationException("Some exception thrown in DoSomething");
   9:     }
  10: }

And here’s the code that sets up Windsor for this service and creates an instance.

   1: var container = new WindsorContainer();
   2: container.Register(
   3:     Component.For<IService>().ImplementedBy<Service>()
   4: );
   5:  
   6: var service = container.Resolve<IService>();
   7: service.DoSomething();

As expected, running this piece of code will print “Doing something” and than fail with an uncaught exception. Now let’s say we want to add an aspect to the code that – in this simple case – prints a message to the console whenever an intercepted method throws an exception. Here’s the simple exception handling aspect from the previous article, which catches exception, prints an information message and optionally re-throws it.

   1: public class ExceptionAspect : IInterceptor {
   2:     public bool EatAll { get; set; }
   3:  
   4:     public void Intercept(IInvocation invocation) {
   5:         try {
   6:             invocation.Proceed();
   7:         } catch (Exception e) {
   8:             Console.WriteLine("{0} caught: {1}", e.GetType(), e.Message);
   9:             if (!EatAll) {
  10:                 throw;
  11:             }
  12:         }
  13:     }
  14: }

 

 

Two automatically inject this aspect into the Service component you only need to add two minor modifications:

1. Register the ExceptionAdvice as a component:

   1: container.Register(
   2:     Component.For<ExceptionAspect>()
   3:     .Parameters(Parameter.ForKey("EatAll").Eq("true"))
   4: );

 

2. Add the Castle.Core.InterceptorAttribute to the Service component:

   1: [Interceptor(typeof(ExceptionAspect))]
   2: public class Service : IService{
   3:     public void DoSomething() {
   4:         Console.WriteLine("Doing something");
   5:         throw new InvalidOperationException("Some exception thrown in DoSomething");
   6:     }
   7: }

This will tell Windsor to automatically create a proxy for the Service component and inject the interceptor of the given type (ExceptionAspect). Running the code now leads to the expected output:

image

Instead of a type you can also provide the key of a component to the InterceptorAttribute.

Simple dynamic injection

 

 

 

If you cannot or don’t want to use attributes – e.g. because you need to disable or enable certain aspects during configuration time – you can of course configure the Windsor container manually.

Let’s add a second aspect, namely a simple logging aspect that prints a message before and after the execution of intercepted methods. This is what our aspect looks like:

   1: public class LoggingAspect : IInterceptor {
   2:     public void Intercept(IInvocation invocation) {
   3:         Console.WriteLine("SomeInterceptor: Before method");
   4:         try {
   5:             invocation.Proceed();
   6:         } finally {
   7:             Console.WriteLine("SomeInterceptor: After method");
   8:         }
   9:     }
  10: }

Now we need to tell Windsor to inject the LoggingAspect into our Service. As with the ExceptionAspect we need to register the advice as a component:

   1: container.Register( Component.For<LoggingAspect>() );

Now we only need to change the registration of the service to inlcude the given aspect:

   1: container.Register(
   2:     Component
   3:     .For<IService>()
   4:     .ImplementedBy<Service>()
   5:     .Interceptors(InterceptorReference.ForType<LoggingAspect>()).Anywhere
   6: );

 

The only change is shown in line 5. The Interceptors() method expects an array of interceptors to apply to the component, Anywhere tells Windsor that we are not interested in the order in which multiple interceptors are applied (see below).

Running the application now yields:

image

 

If you configure the container in source code as shown above you can decide at configuration time which interceptors to inject. Of course, the interceptors can also be configured using an external XML file for full configurability.

If you configure multiple interceptors sometimes the order in which they are applied does matter. For example, assume you have an interceptor that caches method results and another one that secures the method for authorized access. In this case you will want the security interceptor to be applied before the caching interceptor, otherwise unauthorized user might see cached values that they are not allowed to see.  Windsor allows you to explicitly state the relative or absolute order of the configured interceptors.

  • ...Interceptors(interceptors).First
    The defined interceptors are prepended to the current list of interceptors.
  • ...Interceptors(interceptors).Last
    The defined interceptors are append to the current list of interceptors.
  • ...Interceptors(interceptors).AtIndex(x)
    The defined interceptors are inserted at the given index of the current list of interceptors.
  • ...Interceptors(interceptors).Anywhere 
    You don’t care where the interceptors are added.

Fully dynamic injection

You can even go one step further. Instead of defining the interceptors explicitly for the different components, Windsor allows you to install a hook that allows you to define the interceptors for each component on the fly during creation.

You can install that hook by implementing the interface IModelnterceptorsSelector which exposes two methods:

   1: public interface IModelInterceptorsSelector {
   2:     bool HasInterceptors(ComponentModel model);
   3:     InterceptorReference[] SelectInterceptors(ComponentModel model);
   4: }

Before a component is activated, Windsor calls HasInterceptor with the component model. If it returns true Windsor will invoke SelectInterceptors to request the actual interceptor references.

As an exammple, we’ll use another interceptor – TransactionAspect – that is injected with an IModelInterceptorSelector. First, here’s the interceptor:

   1: public class TransactionAspect : IInterceptor {
   2:     public void Intercept(IInvocation invocation) {
   3:         try {
   4:             Console.WriteLine("Opening transaction");
   5:             invocation.Proceed();
   6:             Console.WriteLine("Commit");
   7:         } catch (Exception e) {
   8:             Console.WriteLine("Rollback");
   9:             throw;
  10:         }
  11:     }
  12: }

And here’s our implementation of the IModelInterceptorsSelector:

   1: public class MyInterceptorSelector : IModelInterceptorsSelector {
   2:     public bool HasInterceptors(ComponentModel model) {
   3:         return typeof(TransactionAspect) != model.Implementation &&
   4:             model.Implementation.Namespace.StartsWith("SimpleAopWindsor");
   5:     }
   6:  
   7:     public InterceptorReference[] SelectInterceptors(ComponentModel model) {
   8:         return new[] { InterceptorReference.ForType<TransactionAspect>() };
   9:     }        
  10: }

As you see there’s nothing fancy going on here. HasInterceptors returns true for types in the SimpleAopWindsor namespace that are not TransactionAspect. The check for TransactionAspect is required in this specific case to prevent infinite recursion – otherwise, the TransactionAspect interceptor would be applied to itself.

SelectInterceptors simply returns an array of InterceptorReferences: in this case it contains only one element, ie. a reference to TransactionAspect.

Of course, we need to register the TransactionAspect as a component in Windsor:

   1: container.Register(
   2:     Component.For<TransactionAspect>()                
   3: );

And finally, we need to tell Windsor to use our interceptors selector.

   1: container.Kernel.ProxyFactory.AddInterceptorSelector(
   2:     new MyInterceptorSelector()
   3: );

If we run the application now we’ll see this:

image

What’s important here is the fact that our LoggingAspect and ExceptionAspect seem to be gone. This is important: if IModelInterceptorsSelector.SelectInterceptors returns a non-null array, only those interceptor will be used. Interceptors configured using one of the previously described methods (attributes or registration) will be ignored. If we want those interceptors to be applied as well our IModelnterceptorsSelector needs to return those references explicitly, eg. like this:

   1: public InterceptorReference[] SelectInterceptors(ComponentModel model) {
   2:     var interceptors = new List<InterceptorReference>(model.Interceptors.Count + 1);
   3:     // add all interceptors configured otherwise
   4:     foreach (InterceptorReference inter in model.Interceptors) {
   5:         interceptors.Add(inter);
   6:     }
   7:     // add an additional interceptor
   8:     interceptors.Add(InterceptorReference.ForType<TransactionAspect>());
   9:     
  10:     return interceptors.ToArray();
  11: }

Now our application uses all interceptors:

image

Conclusion

As you’ve seen there are many different ways to inject inspectors into components in a Windsor container, ranging from static definition of inspectors using attributes to fully dynamic injection using IModelInterceptorsSelector.

What’s missing in comparison toclassic” AOP frameworks such as AspectJ? Pointcuts of course! With IModelInterceptorsSelector we are able to choose which types get interceptors applied, but those interceptors intercept every method of the target. We’d like to be able to define something similar to pointcuts to select the methods that get intercepted. And that’s what’s the next article in this series will be about. Stay tuned!

Souce code for this article: SimpleAopWindsor.zip (600.79 kb)

Previous articles:

Posted in: C# | Castle | Patterns

Tags: , ,