A String’s Tale

This is something that went into being as a result of an interesting “Q” faced by a close associate as part of his technical interview. The “Q” being – How would one represent a String as a value type in DotNET to which his answer was an immediate “No, you can’t!”  Theoretically he is correct in DotNET realms and nothing ordinary would mandate you to even think about it.  I guess Mr. Hyde got better off and sent me reeling on such a realization (but still not sure if this was what the interviewer had in mind) to this “Q”.

This has nothing special to pay attention to apart from usage of certain CSharp (C#) language features like Dynamic code generation using Reflection, Extension Methods, LINQ, Anonymous functions etc. TypeAttributes.SequentialLayout (Highlighted line) does have lot of significance the way the structure is created here!

The major short-coming would be the structure itself for String encoding. It would have been ideal to have the structure to just have one field each for every single character and the corresponding positions. The use of bit array was explored but abandoned due to its cap at 32 & 64. I didn’t really spend much time on getting the right structure as this was more an adventure to somehow try and see if it was really possible as opposed to finding a smart way. Any other intelligent encoding schemes or data compression techniques (Huffman coding, Arithmetic coding, LZW coding etc.) would really uplift this adventure to a different level. The journey itself is the reward here!


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace StringVal
{
    public static class StringHelper
    {
        /// <summary>
        /// Returns the Value Type equivalent of a String.
        /// </summary>
        public static ValueType GetValue(this string s)
        {
            int _stringLength = s.Length;
            string _typeName = "StringVal";
            AssemblyName _assemblyName = new AssemblyName();
            _assemblyName.Name = "IamOnTopOfTheWorld";
            AssemblyBuilder _newAssembly =
            System.Threading.Thread.GetDomain().DefineDynamicAssembly(_assemblyName, AssemblyBuilderAccess.Run);
            ModuleBuilder _newModule = _newAssembly.DefineDynamicModule("StringUtils");
            TypeBuilder _newType = _newModule.DefineType(_typeName,
                                 TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.SequentialLayout | TypeAttributes.Serializable,
                                 typeof(ValueType));
            FieldBuilder field;
            for (int i=0;i<_stringLength;i++)
            {
                field = _newType.DefineField(string.Format("c{0}_{1}", i, Char.ConvertToUtf32(s, i)), typeof(bool), FieldAttributes.Public);
            }
            Type type = _newType.CreateType();
            return (ValueType)_newAssembly.CreateInstance(_typeName);
        }

        /// <summary>
        /// Returns the String equivalent of Type :: StringVal
        /// </summary>
        public static string GetString(this ValueType valType)
        {
            string sOutput = @"Error::Expected Value Type-""StringVal""";
            if (valType.GetType().Assembly.GetName().Name.Equals("IamOnTopOfTheWorld") &&
                valType.GetType().Module.ScopeName.Equals("StringUtils") &&
                valType.GetType().Name.Equals("StringVal"))
            {
                var query = from m in valType.GetType().GetFields()
                            select m;
                StringBuilder sBuilder = new StringBuilder(query.Count<FieldInfo>());
                string fldName;
                int utfCharCode;
                foreach (FieldInfo fldInfo in query)
                {
                    fldName = fldInfo.Name;
                    utfCharCode = int.Parse(fldName.Substring(fldName.IndexOf("_") + 1));
                    sBuilder = sBuilder.Append(Char.ConvertFromUtf32(utfCharCode));
                }
                sOutput = sBuilder.ToString();
            }
            return sOutput;
        }

        /// <summary>
        /// Returns the byte size of a structure whose type is 'type', as stored in managed memory.
        /// Courtesy: <a href="http://msdn.microsoft.com/en-us/library/eahchzkf.aspx">MSDN</a>
        /// </summary>
        public static int GetManagedSize(this Type type)
        {
            var method = new DynamicMethod("GetManagedSizeImpl",
              typeof(uint),
              new Type[0],
              false);
            ILGenerator gen = method.GetILGenerator();
            gen.Emit(OpCodes.Sizeof, type);
            gen.Emit(OpCodes.Ret);
            var func = (Func<uint>)method.CreateDelegate(typeof(Func<uint>));
            return checked((int)func());
        }
    }

    /// <summary>
    /// Test Harness!
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            string x = @"Mary had a little lamb!";//Provide your Input String here...
            Console.WriteLine(String.Format(@"Initialized String -> {0}",x));
            ValueType y = x.GetValue();//Converts the string to a value type
            Console.WriteLine(String.Format(@"String Converted to Value of Type -> {0} || Size -> {1} bytes",
                y.GetType().Name,
                y.GetType().GetManagedSize()));
            Console.WriteLine(String.Format(@"Recovered String from it's equivalent Value Type -> {0}",
                y.GetString()));//Converts the value type to String
            Console.Read();
        }
    }
}