C#:dynamic运行时转换

我想实现一个具有以下签名的方法

dynamic Cast(object obj, Type castTo); 

任何人都知道如何做到这一点? obj绝对实现了castTo,但是为了让我的一些应用程序的运行时绑定的东西能够正常工作,需要进行正确的转换。

编辑:如果一些答案没有意义,那是因为我最初意外地input了dynamic Cast(dynamic obj, Type castTo); – 我的意思是input应该是object或其他有保证的基类

我想你在这里混淆铸造和转换的问题。

  • 铸造:改变指向对象的参考types的行为。 向上或向下移动对象层次结构或实现的接口
  • 转换:从不同types的原始源对象中创build一个新对象,并通过对该types的引用来访问它。

通常很难知道C#中2的区别,因为它们都使用相同的C#操作符:转换。

在这种情况下,你几乎肯定不是在寻找一个演员阵容。 将dynamic投射到另一个dynamic本质上是一种身份转换。 它没有提供任何价值,因为你只是获得一个dynamic引用回到同一个底层对象。 由此产生的查找将没有什么不同。

相反,在这种情况下你想要的是转换。 这是将底层对象变形为不同types,并以dynamic方式访问生成的对象。 最好的API是Convert.ChangeType

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

编辑

更新的问题有以下行:

obj绝对实现castTo

如果是这种情况,则Cast方法不需要存在。 源object可以简单地分配给一个dynamic引用。

 dynamic d = source; 

这听起来像你想要完成的是看到一个特定的接口或通过dynamic引用键入source的层次结构。 这根本不可能。 生成的dynamic引用将直接看到实现对象。 它不会查看源的层次结构中的任何特定types。 因此,在层次结构中转换为不同types,然后回到dynamic的想法与仅仅分配给dynamic完全相同。 它仍将指向相同的基础对象。

这应该工作:

 public static dynamic Cast(dynamic obj, Type castTo) { return Convert.ChangeType(obj, castTo); } 

编辑

我写了下面的testing代码:

 var x = "123"; var y = Cast(x, typeof(int)); var z = y + 7; var w = Cast(z, typeof(string)); // w == "130" 

它确实类似于PHP,JavaScript或Python等语言中的“types转换”(因为它也值转换为所需的types)。 我不知道这是不是一件好事,但它肯定有效… 🙂

最好的我到目前为止:

 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; } 

开源框架Dynamitey有一个使用DLR进行后期绑定的静态方法,包括cast转换等 。

 dynamic Cast(object obj, Type castTo){ return Dynamic.InvokeConvert(obj, castTo, explict:true); } 

这比使用reflection调用Cast<T>的优点是,这也适用于任何具有dynamic转换运算符的IDynamicMetaObjectProvider即。 DynamicObject TryConvert

我意识到这已经得到了回答,但我用了一种不同的方法,认为这可能是值得分享的。 另外,我觉得我的方法可能会产生不必要的开销。 但是,我无法观察或计算在我们观察到的负载下发生的任何事情。 我正在寻找这种方法的任何有用的反馈。

dynamic处理的问题在于,您不能直接将任何函数附加到dynamic对象。 你必须使用一些能够弄清楚你不想每次都弄清楚的作业。

在规划这个简单的解决scheme时,我研究了在尝试重新input类似对象时有效的中介是什么。 我发现一个二进制数组,string(xml,json)或硬编码转换( IConvertable )是通常的方法。 由于代码可维护性和懒惰,我不想进入二进制转换。

我的理论是, 牛顿软件可以通过使用string中介做到这一点。

作为缺点,我相当肯定的是,当将string转换为对象时,它会通过search当前程序集中的匹配属性的对象来使用reflection,创buildtypes,然后实例化属性,这将需要更多的reflection。 如果属实,所有这些可以被认为是可以避免的开销。

C#:

 //This lives in a helper class public static ConvertDynamic<T>(dynamic data) { return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Newtonsoft.Json.JsonConvert.SerializeObject(data)); } //Same helper, but in an extension class (public static class), //but could be in a base class also. public static ToModelList<T>(this List<dynamic> list) { List<T> retList = new List<T>(); foreach(dynamic d in list) { retList.Add(ConvertDynamic<T>(d)); } } 

这就是说,这适合我放在一起的另一个实用工具,可以让我把任何对象变成dynamic的。 我知道我必须使用reflection来正确地做到这一点:

 public static dynamic ToDynamic(this object value) { IDictionary<string, object> expando = new ExpandoObject(); foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) expando.Add(property.Name, property.GetValue(value)); return expando as ExpandoObject; } 

我必须提供这个function。 分配给dynamictypes化variables的任意对象不能转换为IDictionary,并且会破坏ConvertDynamic函数。 对于要使用的这个函数链,必须提供一个dynamic的System.Dynamic.ExpandoObject或者IDictionary <string,object>。

尝试一个通用的:

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

这是扩展方法的格式,所以它的用法就好像它是dynamic对象的成员一样:

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

编辑:Grr,没有看到。 是的,你可以反思性地closuresgenerics,并且隐藏在非generics扩展方法中并不难:

 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 }); } 

我只是不确定你会从中得到什么。 基本上,你正在采取一种dynamic的方式,强制一个演员转换成一个reflection型,然后把它填充回来。 也许你是对的,我不应该问。 但是,这可能会做你想要的。 基本上,当你进入dynamic土地时,你会失去执行大多数施放操作的需要,因为你可以通过reflection方法或反复试验来发现对象是什么,所以没有多less优雅的方法来做到这一点。

或者:

 public static T Cast<T>(this dynamic obj) where T:class { return obj as T; }