我想要实现一个具有以下签名的方法
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
或其他保证的基类。
我认为您在混淆强制类型转换和类型转换的问题。
在C#中,很难区分这两个概念,因为它们都使用相同的C#运算符:强制类型转换操作符。
在这种情况下,您几乎肯定不是在寻找一个强制类型转换操作。将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
引用将直接查看实现对象,而不会浏览source层次结构中的任何特定类型。因此,在层次结构中转换为不同类型,然后再返回dynamic
的想法与一开始直接赋值给dynamic
完全相同。它仍然指向相同的基础对象。
dynamic
呢?如果底层操作确实是一个转换,那就不需要这个方法。 - JaredParDynamicConvert
或类似的名称。 - phil soady这应该可以正常工作:
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
(这是一个类,而不是值类型)。 - rsenna我知道这个问题已经有答案了,但是我使用了不同的方法,认为值得分享。另外,我觉得我的方法可能会产生一些不必要的开销。但是,在我们观察到的负载下,我无法观察或计算到任何糟糕的情况发生。我正在寻找对这种方法的任何有用反馈。
处理动态对象的问题在于您无法直接将任何函数附加到动态对象。您必须使用某些东西来确定您不想每次都弄清楚的分配。
在规划这个简单的解决方案时,我看了看当试图重新输入类似对象时的有效中介物是什么。我发现二进制数组、字符串(xml、json)或硬编码转换(IConvertable)是通常的方法。我不想涉及二进制转换,因为它会影响代码可维护性和懒惰。
我的理论是,Newtonsoft 可以通过使用字符串媒介来实现这一点。
作为一个缺点,我相当确定在将字符串转换为对象时,它会通过搜索当前程序集中具有匹配属性的对象来使用反射,创建类型,然后实例化属性,这将需要更多的反射。如果是真的,所有这些都可以被认为是可避免的开销。
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>类型的动态对象。
到目前为止,我得到的最好结果:
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;
}
obj
(其编译时类型为object
)不是Foo
的情况下,您会得到一个空引用外,调用DynamicCast(obj, typeof(Foo))
和(dynamic)obj
有什么区别? 此外,约束where T:object
毫无意义且不允许。 - Jeppe Stig NielsenPerson
类,其中包含一个 GetFullName
方法,以及一个 Professor : Person
类,它重写了 GetFullName
方法并在后面添加了 "PhD" 后缀。现在假设该实体的类型为 Professor
,但在我们的方法之外被强制转换为 Person
,可能是由 ORM 或模型绑定器等加载的。如果你调用 ((dynamic)entity).GetFullName()
,它将运行 Person.GetFullName()
。这个问题已经很久没有出现过了,所以具体细节可能有点不对,但与此有关。 - George MauerProfessor
和Person
示例必然涉及类,而不是结构体。其次,如果Professor
覆盖该方法,虚拟调度将确保使用“最派生”的实现。即使发生了方法隐藏,上面的DynamicCast
方法也没有用处。在所有情况下,DynamicCast(obj, typeof(Foo))
等同于(obj is Foo) ? (dynamic)obj : null
。只需使用(dynamic)obj
即可。 - Jeppe Stig Nielsenx
是派生类的实例时,您似乎相信(dynamic)(BaseClass)x
和(dynamic)(DerivedClass)x
的行为可能不同。但是这种差异应该从何处来呢?对象不会记住曾经引用它的引用类型。 - Jeppe Stig Nielsendynamic Cast(object obj, Type castTo){
return Dynamic.InvokeConvert(obj, castTo, explict:true);
}
Cast<T>
相比,这种方法的优点在于它也适用于任何具有动态转换运算符的IDynamicMetaObjectProvider
,例如DynamicObject
上的TryConvert。尝试使用通用方法:
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);
编辑:糟糕,没有看到那个。是的,您可以反射性地关闭泛型,并且在非泛型扩展方法中隐藏它并不难:
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
的类型,则此方法(无需反射)无法正常工作。 - jason 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);
在 @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 T Cast<T>(this dynamic obj) where T:class
{
return obj as T;
}