3

I'm trying to use a BinaryReader Read method in a generic way. Only at run time I know the type of data being read.

   public static T ReadData<T>(string fileName)
        {
            var value = default(T);

            using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                using (var reader = new BinaryReader(fs))
                {
                    if (typeof (T).GetGenericTypeDefinition() == typeof (Int32))
                    {
                        value = (dynamic) reader.ReadInt32();
                    }
                    if (typeof (T).GetGenericTypeDefinition() == typeof (string))
                    {
                        value = (dynamic) reader.ReadString();
                    }
                    // More if statements here for other type of data
                }
            }
            return value ;
        }  

How can I avoid the multiple if statements?

Monica
  • 223
  • 1
  • 3
  • 14
  • What are the calls to `GetGenericTypeDefinition` there for? If `T` is a generic type, it sure wasn't constructed from either `System.Int32` or `System.String`, because those aren't generic type definitions. On the other hand, if `T` *is* `Int32` or `String`, `GetGenericTypeDefinition` will throw an `InvalidOperationException` as you're calling it on non-generic types. – O. R. Mapper Nov 30 '12 at 19:29
  • Also, that is a good example of how *not* to use generics - overloads with all the types to support are a better solution here, they make all the manual type checking with chained `if`s obsolete. – O. R. Mapper Nov 30 '12 at 19:30

1 Answers1

1

Other than using reflection (which would be slow), the only option I can think of that you might like better would be to build a dictionary:

static object s_lock = new object();
static IDictionary<Type, Func<BinaryReader, dynamic>> s_readers = null;
static T ReadData<T>(string fileName)
{
    lock (s_lock)
    {
        if (s_readers == null)
        {
            s_readers = new Dictionary<Type, Func<BinaryReader, dynamic>>();
            s_readers.Add(typeof(int), r => r.ReadInt32());
            s_readers.Add(typeof(string), r => r.ReadString());
            // Add more here
        }
    }

    if (!s_readers.ContainsKey(typeof(T))) throw new ArgumentException("Invalid type");

    using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
    using (var reader = new BinaryReader(fs))
    {
        return s_readers[typeof(T)](reader);
    }
}

The code where you call this will be cleaner, but you're still stuck having to map each Read function to a type.

Jon B
  • 51,025
  • 31
  • 133
  • 161