C#: Dynamic runtime cast

前端 未结 9 2119
情深已故
情深已故 2020-11-27 03:50

I would like to implement a method with the following signature

dynamic Cast(object obj, Type castTo);

Anyone know how to do that? obj defi

相关标签:
9条回答
  • 2020-11-27 03:53

    Best I got so far:

    dynamic DynamicCast(object entity, Type to)
    {
        var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic);
        var closeCast = openCast.MakeGenericMethod(to);
        return closeCast.Invoke(entity, new[] { entity });
    }
    static T Cast<T>(object entity) where T : class
    {
        return entity as T;
    }
    
    0 讨论(0)
  • 2020-11-27 03:55

    Alternatively:

    public static T Cast<T>(this dynamic obj) where T:class
    {
       return obj as T;
    }
    
    0 讨论(0)
  • 2020-11-27 04:00

    Slight modification on @JRodd version to support objects coming from Json (JObject)

    public static dynamic ToDynamic(this object value)
        {
            IDictionary<string, object> expando = new ExpandoObject();
    
            //Get the type of object 
            Type t = value.GetType();
    
            //If is Dynamic Expando object
            if (t.Equals(typeof(ExpandoObject)))
            {
                foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
                    expando.Add(property.Name, property.GetValue(value));
            }
            //If coming from Json object
            else if (t.Equals(typeof(JObject)))
            {
                foreach (JProperty property in (JToken)value)
                    expando.Add(property.Name, property.Value);
            }
            else //Try converting a regular object
            {
                string str = JsonConvert.SerializeObject(value);
                ExpandoObject obj = JsonConvert.DeserializeObject<ExpandoObject>(str);
    
                return obj;
            }
    
           
    
            return expando as ExpandoObject;
        }
    
    0 讨论(0)
  • 2020-11-27 04:06

    You can use the expression pipeline to achieve this:

     public static Func<object, object> Caster(Type type)
     {
        var inputObject = Expression.Parameter(typeof(object));
        return Expression.Lambda<Func<object,object>>(Expression.Convert(inputObject, type), inputPara).Compile();
     }
    

    which you can invoke like:

    object objAsDesiredType = Caster(desiredType)(obj);
    

    Drawbacks: The compilation of this lambda is slower than nearly all other methods mentioned already

    Advantages: You can cache the lambda, then this should be actually the fastest method, it is identical to handwritten code at compile time

    0 讨论(0)
  • 2020-11-27 04:07

    I think you're confusing the issues of casting and converting here.

    • Casting: The act of changing the type of a reference which points to an object. Either moving up or down the object hierarchy or to an implemented interface
    • Converting: Creating a new object from the original source object of a different type and accessing it through a reference to that type.

    It's often hard to know the difference between the 2 in C# because both of them use the same C# operator: the cast.

    In this situation you are almost certainly not looking for a cast operation. Casting a dynamic to another dynamic is essentially an identity conversion. It provides no value because you're just getting a dynamic reference back to the same underlying object. The resulting lookup would be no different.

    Instead what you appear to want in this scenario is a conversion. That is morphing the underlying object to a different type and accessing the resulting object in a dynamic fashion. The best API for this is Convert.ChangeType.

    public static dynamic Convert(dynamic source, Type dest) {
      return Convert.ChangeType(source, dest);
    }
    

    EDIT

    The updated question has the following line:

    obj definitely implements castTo

    If this is the case then the Cast method doesn't need to exist. The source object can simply be assigned to a dynamic reference.

    dynamic d = source;
    

    It sounds like what you're trying to accomplish is to see a particular interface or type in the hierarchy of source through a dynamic reference. That is simply not possible. The resulting dynamic reference will see the implementation object directly. It doesn't look through any particular type in the hierarchy of source. So the idea of casting to a different type in the hierarchy and then back to dynamic is exactly identical to just assigning to dynamic in the first place. It will still point to the same underlying object.

    0 讨论(0)
  • 2020-11-27 04:08

    Try a generic:

    public static T CastTo<T>(this dynamic obj, bool safeCast) where T:class
    {
       try
       {
          return (T)obj;
       }
       catch
       {
          if(safeCast) return null;
          else throw;
       }
    }
    

    This is in extension method format, so its usage would be as if it were a member of dynamic objects:

    dynamic myDynamic = new Something();
    var typedObject = myDynamic.CastTo<Something>(false);
    

    EDIT: Grr, didn't see that. Yes, you could reflectively close the generic, and it wouldn't be hard to hide in a non-generic extension method:

    public static dynamic DynamicCastTo(this dynamic obj, Type castTo, bool safeCast)
    {
       MethodInfo castMethod = this.GetType().GetMethod("CastTo").MakeGenericMethod(castTo);
       return castMethod.Invoke(null, new object[] { obj, safeCast });
    }
    

    I'm just not sure what you'd get out of this. Basically you're taking a dynamic, forcing a cast to a reflected type, then stuffing it back in a dynamic. Maybe you're right, I shouldn't ask. But, this'll probably do what you want. Basically when you go into dynamic-land, you lose the need to perform most casting operations as you can discover what an object is and does through reflective methods or trial and error, so there aren't many elegant ways to do this.

    0 讨论(0)
提交回复
热议问题