Performance of object-to-string conversion
(I've made a few assumptions, so please correct me if I'm wrong.)

Let's suppose we have the following types:

public class Foo
{
    public int Id { get; set; }

    [Signed]
    public DateTime Timestamp { get; set; }

    [Signed]
    public string Name { get; set; }

    [Signed]
    public decimal Price { get; set; }

    [Signed]
    public SomeEnum Thing { get; set; }
}

public enum SomeEnum
{
    One = 1,
    Two,
    Three
}

public class SignedAttribute : Attribute
{
}


We want to hash the Signed properties of an instance of Foo (actually, many instances of Foo).

I assume you're currently getting these properties via reflection. Something like this:

var properties = typeof(Foo)
    .GetProperties()
    .Where(p =&gt; Attribute.IsDefined(p, typeof(SignedAttribute)))
    .OrderBy(p =&gt; p.Name)
    .ToArray();

// ...

var sb = new StringBuilder();
foreach (var property in properties)
{
    sb.Append(ValueToString(property.GetValue(foo)));
}

var bytes = Encoding.UTF8.GetBytes(sb.ToString());
md5.TransformBlock(bytes, 0, bytes.Length, bytes, 0);


Let's set up a test to see how long this takes

var foo = new Foo
{
    Id = 1,
    Name = "Thing",
    Price = 123.45m,
    Thing = SomeEnum.Two,
    Timestamp = new DateTime(2015, 04, 07)
};

byte[] hash;
var sw = Stopwatch.StartNew();
using (var md5 = MD5.Create())
{
    for (var i = 0; i &lt; 300000; i++)
    {
        var sb = new StringBuilder();
        foreach (var property in properties)
        {
            sb.Append(ValueToString(property.GetValue(foo)));
        }

        var bytes = Encoding.UTF8.GetBytes(sb.ToString());
        md5.TransformBlock(bytes, 0, bytes.Length, bytes, 0);
    }

    md5.TransformFinalBlock(new byte[0], 0, 0);
    hash = md5.Hash;
}

sw.Stop();


Here ValueToString is the code as posted in your question. On my machine, I get a time of 0.8s.

How much better can we do? Suppose we could cheat and use the following method:

private static string FooToString(Foo foo)
{
    var sb = new StringBuilder();
    sb.Append(foo.Name);
    sb.Append(foo.Price.ToString(
        "0.############################",
        CultureInfo.InvariantCulture));
    sb.Append(((int) foo.Thing).ToString("X"));
    sb.Append(foo.Timestamp.Ticks.ToString("X"));
    return sb.ToString();
}


So now our loop looks like this:

for (var i = 0; i &lt; 300000; i++)
{
    var value = FooToString(foo);
    var bytes = Encoding.UTF8.GetBytes(value);
    md5.TransformBlock(bytes, 0, bytes.Length, bytes, 0);
}


I get a time of 0.36s, which I'll take as the baseline.

Great, but let's assume we can't write FooToString. We can create an equivalent method dynamically.

We introduce some helper methods:

public static string ValueToString(string value)
{
    return value ?? string.Empty;
}

public static string ValueToString(Enum value)
{
    return Convert.ToInt32(value).ToString("X");
}

public static string ValueToString(decimal value)
{
    return value.ToString("0.############################", CultureInfo.InvariantCulture);
}

public static string ValueToString(DateTime value)
{
    return value.Ticks.ToString("X");
}


And then create the method dynamically, using reflection to find the properties of Foo that have the Signed attribute.

var properties = (typeof(Foo))
    .GetProperties()
    .Where(p =&gt; Attribute.IsDefined(p, typeof(SignedAttribute)))
    .OrderBy(p =&gt; p.Name)
    .ToArray();

var getSignatureMethod = new DynamicMethod(
    "GetSignature",
    typeof(string),
    new[] { typeof(Foo) },
    typeof(Foo).Module);

var generator = getSignatureMethod.GetILGenerator();
generator.DeclareLocal(typeof(StringBuilder));
generator.Emit(OpCodes.Newobj, typeof(StringBuilder).GetConstructor(Type.EmptyTypes));
generator.Emit(OpCodes.Stloc_0);
generator.Emit(OpCodes.Ldloc_0);

var append = typeof(StringBuilder).GetMethod("Append", new[] { typeof (string) });
foreach (var property in properties)
{
    generator.Emit(OpCodes.Ldarg_0);
    generator.Emit(OpCodes.Callvirt, property.GetGetMethod());
    if (property.PropertyType.BaseType == typeof(Enum))
    {
        generator.Emit(OpCodes.Box, property.PropertyType);
    }

    generator.Emit(OpCodes.Call, typeof(Program).GetMethod("ValueToString", new[] { property.PropertyType }));
    generator.Emit(OpCodes.Callvirt, append);
}

generator.Emit(OpCodes.Pop);
generator.Emit(OpCodes.Ldloc_0);
generator.Emit(OpCodes.Callvirt, typeof(object).GetMethod("ToString", new Type[] { }));
generator.Emit(OpCodes.Ret);

var getSignature = (Func&lt;Foo, string&gt;)
    getSignatureMethod.CreateDelegate(typeof(Func&lt;Foo, string&gt;));


(I haven't worked with dynamically generated code before, there might be some things that could be improved.)

Now our loop looks like this:

for (var i = 0; i &lt; 300000; i++)
{
    var value = getSignature(foo);
    var bytes = Encoding.UTF8.GetBytes(value);
    md5.TransformBlock(bytes, 0, bytes.Length, bytes, 0);
}


And on my machine, it takes 0.39s, which is pretty close to the baseline.

I've put the code up on Github if you want to play around with it.