One problem with C# generics is the lack of member constraints. In other words, this is impossible:
public static T Add<T>(T left, T right)
{
    return left + right;
}
People have come up with a large number of solutions, but they all have their own problems, ranging from messy looking syntax to less-than-optimal performance (particularly due to virtual function calls). The solution I propose is a somewhat hacky one (yes that's a word) which maintains both good performance and clean looking code: write the function in IL.

The code for the add method boils down to something like this:
ldarg.0
ldarg.1
add
ret
For those not familiar with IL, the above code adds the first to arguments of the method, then returns the result.

I found that this actually works with generic types. No funny errors, no nothing. Of course, I didn't actually compile any IL source code - I wrote a separate program to generate the assembly. The source code for it is this:
namespace Generator
{
    using System;
    using System.Linq;
    using System.Reflection;
    using System.Reflection.Emit;

    public static class Program
    {
        public static void Main()
        {
            var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Operations"), AssemblyBuilderAccess.Save);
            var module = assemblyBuilder.DefineDynamicModule("Operations", "Operations.dll");
            var type = module.DefineType("Operator", TypeAttributes.Public | TypeAttributes.Sealed);

            type.DefineBinaryOperatorMethod("Add", OpCodes.Add);
            type.DefineBinaryOperatorMethod("Subtract", OpCodes.Sub);
            type.DefineBinaryOperatorMethod("Multiply", OpCodes.Mul);
            type.DefineBinaryOperatorMethod("Divide", OpCodes.Div);
            type.DefineBinaryOperatorMethod("Remainder", OpCodes.Rem);
            type.CreateType();

            assemblyBuilder.Save("Operations.dll");
        }

        private static MethodBuilder DefineBinaryOperatorMethod(this TypeBuilder type, string name, OpCode operation)
        {
            var method = type.DefineMethod(name, MethodAttributes.Public | MethodAttributes.Static);
            var genericParameter = method.DefineGenericParameters("T").First();
            genericParameter.SetBaseTypeConstraint(typeof(ValueType));
            
            method.SetReturnType(genericParameter);
            method.SetParameters(genericParameter, genericParameter);
            method.DefineParameter(1, ParameterAttributes.None, "left");
            method.DefineParameter(2, ParameterAttributes.None, "right");

            var ilGenerator = method.GetILGenerator();
            var continueLabel = ilGenerator.DefineLabel();

            ilGenerator.Emit(OpCodes.Ldtoken, genericParameter);
            ilGenerator.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"), null);
            ilGenerator.EmitCall(OpCodes.Callvirt, typeof(Type).GetProperty("IsPrimitive").GetGetMethod(), null);
            ilGenerator.Emit(OpCodes.Brtrue_S, continueLabel);
            ilGenerator.Emit(OpCodes.Ldstr, "The specified type is not supported by this operation.");
            ilGenerator.Emit(OpCodes.Newobj, typeof(ArgumentException).GetConstructor(new[] { typeof(string) }));
            ilGenerator.Emit(OpCodes.Throw);
            ilGenerator.MarkLabel(continueLabel);
            ilGenerator.Emit(OpCodes.Ldarg_0);
            ilGenerator.Emit(OpCodes.Ldarg_1);
            ilGenerator.Emit(operation);
            ilGenerator.Emit(OpCodes.Ret);

            return method;
        }
    }
}
In case your wondering what the ldtoken/call/callvirt/brtrue.s/ldstr/newobj/throw stuff is doing there, that just checks to make sure the type argument is a primitive type (yes this only works on primitive types), and throws an ArgumentException otherwise. Before adding that, .NET threw some pretty nasty exceptions when I tried it on some non-primitive types.

As a final note, the methods generated with indeed work on all primitive types. Even booleans. I was surprised to get a DivideByZeroException upon attempting this:
Operator.Divide(true, false);
Again, this only works on primitive types. Remember, string and decimal are not primitive types. Perhaps this could be extended to calling the op_* functions...

After a couple small performance tests, I found that this method was nearly as fast as doing simple addition (x + y). Then again, I know nothing about microbenchmarks. Try it for yourself :D

Enjoy
1

View comments

Well, I got tired of Blogger :D. New blog here.

While developing spectral, I discovered something peculiar.

Consider this sample pseudo C#/IL:

public static T Sqrt<T>(T value) { ldarg.0 conv.r8 call double System.Math.Sqrt(double) ret } You'd expect some sort of error, right? The return type is T, but the returned value is a double.

Turns out it runs fine. What's more, you don't even need the conv.r8 instruction.

I have to say, IL's flexibility is amazing.

I decided to shove my findings in the last post into a library, dubbed Spectral.

Download the latest change set here.

One problem with C# generics is the lack of member constraints. In other words, this is impossible:

public static T Add<T>(T left, T right) { return left + right; } People have come up with a large number of solutions, but they all have their own problems, ranging from messy looking syntax to less-than-optimal performance (particularly due to virtual function calls).
1

A very funny thing happened today.

I believe in some language or another (can't remember which), the Abs function is actually a member function - x.abs() instead of abs(x). It also means you can do something like -1.abs(). I wanted to try to emulate that sort of thing with extensions methods. So, I wrote this:

public static int Abs(this int value) { return Math.Abs(value); }

Simple enough.

Something wonderfully terrible happened today: I got reviewed.

A negative review, yes. But also a very stupid one.

The reviewer complains that the s/he can't compile the source because it won't load in VS2010.

Keep in mind this is a somewhat old game that I made quite some time ago, using... XNA 3.0.

And of course, v3.0 was for VS2008... does not, and never will, work with 2010...

On the bright side, I now have all the motivation I need to create a new version of the game.

This has been done a thousand times, but here goes anyway...

Ok, sort of. After much experimenting, this is the simplest method I could come up with.

This method uses linear depth, and reconstructs the position in world space.

To store the position:

/* Vertex Shader */ float4 viewPosition = mul(input.Position, mul(World, View)); output.Depth = (-viewPosition.z - NearPlane) / (FarPlane - NearPlane); /* Pixel Shader */ output.Depth = input.Depth; // Um... yeah... just output the depth...
1

Say you have a simple class which implements the singleton pattern.

Now you want to create a class which inherits the singleton functionality.

So, you call Derived.GetInstance() and... you get an instance of a Singleton, not a Derived!!

An interesting (and somewhat wacky) solution to this problem:

The Curiously Reccuring Template Pattern

Trust me, it compiles. Now, calling Derived.GetInstance() returns an instance of Derived, not Singleton.

In an effort to emulate Reactive Programming, I have created this nifty little class. It's preliminary (created five minutes ago), but seems useful enough for now.

Every once in a while, I run into this sort of ugly situation:

public MyClass(GraphicsDevice graphicsDevice)

: this(graphicsDevice, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height)

{ }

public MyClass(GraphicsDevice graphicsDevice, int width, int height)

{

if (graphicsDevice == null)

throw new ArgumentNullException("graphicsDevice");

// etc.

}

I just want to do a basic check. Throw an exception if graphicsDevice is null. Simple enough.
Blog Archive
Active Projects
Active Projects
Total Pageviews
Total Pageviews
10816
Loading