While some people argue against the use of generics for things like you describe, there are times when they are appropriate. Nonetheless, there isn't a particularly convenient pattern for having different code execute for different types. Probably the best approach is to have your private static Action<T> readProc = InitReadProc; and have the generic ReadValue(T val) call readProc(val). The InitReadProc method could look something like:
ReadFile<float>.readProc = readValue; // Binds to `float` overload
ReadFile<double>.readProc = readValue; // Binds to `double` overload
// etc. for all known overloads
if (readProc == InitReadProc) // The readProc of *this* type (T) didn't get set above
throw new NotSupportedException(String.Format("Type {0} not available", typeof(T));
else
readProc();
Using this approach, the first time any attempt is made to call the generic readValue for any type, it will fill in the readProc delegates for all known types. Any future attempt to call readValue on any such type will be dispatched via the delegate to the appropriate method. Note that if desired one could offer a ConfigureReadProc<T>(Action<T> proc) method to allow consumers of the class to set up ReadFile methods for other types. One could also if desired use Reflection to check whether type T supported a static readValue(T) method and, if so, attach the delegate to that.