0

This is a follow-up to How to invoke static method in C#4.0 with dynamic type?

Is there a way to remove duplication when working with double.MaxValue, int.MaxValue, etc. by using dynamic keyword and/or generics?

Contrived example:

  T? Transform<T>(Func<T?> continuation)
     where T : struct
  {
     return typeof(T).StaticMembers().MaxValue;
  }
Community
  • 1
  • 1
GregC
  • 7,737
  • 2
  • 53
  • 67
  • 1
    @GregC in .net constants are not compile time. – Andrey Apr 21 '11 at 20:25
  • @Andrey: I updated my Q with an example – GregC Apr 21 '11 at 20:27
  • 1
    @GregC - The field or variable *declaration* (i.e. the member marked as `const`) is still part of the metadata. All *usages* of that constant is replaced with the literal value by the compiler. That being said I still don't quite understand the duplication issue you are trying to solve. – Andrew Hare Apr 21 '11 at 20:28
  • @GregC it is not duplication, it is called ambiguity. – Andrey Apr 21 '11 at 20:28
  • 1
    Some of you guys seem really confused. The question seems clear enough to me. He has a method that can work with a variety of numeric types, and no matter which type it takes, he wants to get the static `MaxValue` property on that type. The alternative involves a lot of duplication because it would mean writing an overload for each individual type. – mqp Apr 21 '11 at 20:30

2 Answers2

1

Modify class StaticMembersDynamicWrapper in this way:

  public override bool TryGetMember(GetMemberBinder binder, out object result) { 
    PropertyInfo prop = _type.GetProperty(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public); 
    if (prop == null) { 
        FieldInfo field = _type.GetField(binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public); 
        if (field == null)
        {
            result = null;
            return false; 
        }
        else
        {
            result = field.GetValue(null, null);
            return true; 
        }
    } 

    result = prop.GetValue(null, null); 
    return true; 
}

Problem of your code is that it only retrieves properties, but constants are actually fields.

Andrey
  • 59,039
  • 12
  • 119
  • 163
0

With a little style and flair, same code:

  public override bool TryGetMember(GetMemberBinder binder, out object result)
  {
     PropertyInfo prop = _type.GetProperty(binder.Name,
        BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);

     if (prop != null)
     {
        result = prop.GetValue(null, null);
        return true;
     }

     FieldInfo field = _type.GetField(binder.Name,
        BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);

     if (field != null)
     {
        result = field.GetValue(null);
        return true;
     }

     result = null;
     return false;
  }

And a cache class, to avoid creating unneeded objects:

public static class StaticMembersDynamicWrapperExtensions
{
   static Dictionary<Type, DynamicObject> cache = 
      new Dictionary<Type, DynamicObject>
      {
         {typeof(double), new StaticMembersDynamicWrapper(typeof(double))},
         {typeof(float), new StaticMembersDynamicWrapper(typeof(float))},
         {typeof(uint), new StaticMembersDynamicWrapper(typeof(uint))},
         {typeof(int), new StaticMembersDynamicWrapper(typeof(int))},
         {typeof(sbyte), new StaticMembersDynamicWrapper(typeof(sbyte))}
      };

   /// <summary>
   /// Allows access to static fields, properties, and methods, resolved at run-time.
   /// </summary>
   public static dynamic StaticMembers(this Type type)
   {
      DynamicObject retVal;
      if (!cache.TryGetValue(type, out retVal))
         return new StaticMembersDynamicWrapper(type);

      return retVal;
   }
}
GregC
  • 7,737
  • 2
  • 53
  • 67