我想用以下签名实现一个方法
dynamic Cast(object obj, Type castTo);
有人知道该怎么做吗?obj肯定实现了castTo,但是需要正确地进行强制转换才能使我的应用程序的某些运行时绑定工作解决。
编辑:如果某些答案没有意义,那是因为我最初不小心键入了dynamic Cast(dynamic obj, Type castTo);
-我的意思是输入应该是object
或其他保证的基类
我想用以下签名实现一个方法
dynamic Cast(object obj, Type castTo);
有人知道该怎么做吗?obj肯定实现了castTo,但是需要正确地进行强制转换才能使我的应用程序的某些运行时绑定工作解决。
编辑:如果某些答案没有意义,那是因为我最初不小心键入了dynamic Cast(dynamic obj, Type castTo);
-我的意思是输入应该是object
或其他保证的基类
Answers:
我认为您在此混淆了转换和转换的问题。
通常很难知道C#中2之间的区别,因为它们都使用相同的C#运算符:强制转换。
在这种情况下,几乎可以肯定您不希望进行强制转换操作。将a强制转换dynamic
为另一个dynamic
实质上是身份转换。它没有任何价值,因为您只是获得dynamic
对相同基础对象的引用。最终的查询没有什么不同。
相反,在这种情况下,您似乎想要的是一次转换。那就是将基础对象变形为其他类型,并以某种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;
听起来您要完成的工作就是source
通过dynamic
引用查看层次结构中的特定接口或类型。那根本不可能。生成的dynamic
参考将直接看到实现对象。它不会在源层次结构中查看任何特定类型。因此,在层次结构中强制转换为其他类型然后再返回的想法与首先dynamic
分配给完全相同dynamic
。它仍将指向相同的基础对象。
dynamic
直接转换为?如果基础操作确实是
DynamicConvert
或类似。
这应该工作:
public static dynamic Cast(dynamic obj, Type castTo)
{
return Convert.ChangeType(obj, castTo);
}
编辑
我编写了以下测试代码:
var x = "123";
var y = Cast(x, typeof(int));
var z = y + 7;
var w = Cast(z, typeof(string)); // w == "130"
它类似于那种在PHP,JavaScript的或Python语言的“类型转换”一个人发现的(因为它也转换价值所需的类型)。我不知道这是否是件好事,但它确实可以工作... :-)
String
(它是一个类,而不是值类型)。
到目前为止我所能获得的最好成绩:
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;
}
DynamicCast(obj, typeof(Foo))
与的区别是什么(dynamic)obj
,除了在obj
(具有编译时类型object
)不是n的情况下获得空引用的情况下,该调用有什么不同Foo
?而且,该约束where T : object
是无意义的并且是不允许的。
Person
一个GetFullName
方法和Professor : Person
它覆盖GetFullName
与“博士”的后缀它。现在假设该实体是类型,Professor
但被强制转换为Person
我们方法的外部,也许这就是ORM或模型绑定程序或其他东西加载实体的方式。如果您调用((dynamic)entitity).GetFullName()
它将运行Person.GetFullName()
。自从这个问题出现以来已经有很长时间了,所以具体情况可能有点不对,但是这与此有关。
Professor
并且Person
必然涉及类,而不涉及结构。其次,如果Professor
重写该方法,则虚拟调度将确保使用“最派生”实现。即使发生了方法隐藏,DynamicCast
上面的方法也无济于事。在所有情况下,DynamicCast(obj, typeof(Foo))
似乎都等效于(obj is Foo) ? (dynamic)obj : null
。只需使用(dynamic)obj
。
(dynamic)(BaseClass)x
可以具有不同的行为(dynamic)(DerivedClass)x
时,x
是的一个实例DerivedClass
。但是,这种差异应从何而来?该对象不记得曾经引用过什么类型的引用。
我知道已经解决了这个问题,但是我使用了不同的方法,并认为值得分享。另外,我觉得我的方法可能会产生不必要的开销。但是,在我们观察到的负载下,我无法观察或计算出任何糟糕的事情。我一直在寻找有关此方法的任何有用反馈。
使用动力学的问题在于您不能直接将任何函数附加到动态对象。您必须使用一些可以计算出您不想每次都分配的作业。
在计划这个简单的解决方案时,我研究了尝试重新键入相似对象时有效的中介机构。我发现二进制数组,字符串(xml,json)或对转换进行硬编码(IConvertable)是常用的方法。由于代码的可维护性因素和懒惰,我不想进入二进制转换。
我的理论是,Newtonsoft可以通过使用字符串中介程序来做到这一点。
不利的一面是,我相当确定将字符串转换为对象时,它将通过在当前程序集中搜索具有匹配属性的对象来使用反射,创建类型,然后实例化属性,这将需要更多反射。如果为true,则所有这些都可以视为可避免的开销。
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));
}
}
话虽如此,这适合我组合在一起的另一个实用程序,使我可以将任何对象变成动态对象。我知道我必须使用反射来正确地做到这一点:
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;
}
我必须提供该功能。分配给动态类型变量的任意对象都不能转换为IDictionary,这会破坏ConvertDynamic函数。为了使用此功能链,必须为其提供动态的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 myDynamic = new Something();
var typedObject = myDynamic.CastTo<Something>(false);
编辑:Grr,没有看到。是的,您可以反射性地关闭泛型,并且不难隐藏在非泛型扩展方法中:
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 });
}
我只是不确定您将从中得到什么。基本上,您采用的是动态方式,将强制类型转换强制为反射类型,然后将其填充回动态方式。也许你是对的,我不应该问。但是,这可能会做您想要的。基本上,当您进入动态着陆时,您无需执行大多数投射操作,因为您可以通过反射方法或反复试验来发现对象是什么,做什么,因此没有很多优雅的方法可以做到这一点。
T
编译类型未知,这将不起作用(无反射)。
对@JRodd版本进行少量修改以支持来自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;
}
您可以使用表达式管道来实现此目的:
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();
}
您可以像这样调用:
object objAsDesiredType = Caster(desiredType)(obj);
缺点:该lambda的编译速度比已经提到的几乎所有其他方法都要慢
优点:您可以缓存lambda,这实际上应该是最快的方法,它与编译时的手写代码相同