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