C#:动态运行时强制转换

Geo*_*uer 61 c# casting c#-4.0

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

dynamic Cast(object obj, Type castTo);
Run Code Online (Sandbox Code Playgroud)

谁知道怎么做?obj肯定实现了castTo,但是需要正确地进行转换才能使我的应用程序的运行时绑定工作得以实现.

编辑:如果一些答案没有意义,那是因为我最初不小心输入dynamic Cast(dynamic obj, Type castTo);- 我的意思是输入应该是object或其他一些保证基类

Jar*_*Par 92

我认为你在这里混淆铸造和转换的问题.

  • 强制转换:更改指向对象的引用类型的行为.向上或向下移动对象层次结构或向已实现的接口移动
  • 转换:从不同类型的原始源对象创建新对象,并通过对该类型的引用访问它.

通常很难知道C#中的2之间的区别,因为它们都使用相同的C#运算符:强制转换.

在这种情况下,你几乎肯定不会寻找演员表演.将a 转换dynamic为另一个dynamic本质上是一种身份转换.它没有提供任何价值,因为您只是将dynamic引用返回到同一个底层对象.结果查找将没有什么不同.

相反,您在此方案中看起来想要的是转换.这是将底层对象变形为不同类型并以某种dynamic方式访问结果对象.对此最好的API是Convert.ChangeType.

public static dynamic Convert(dynamic source, Type dest) {
  return Convert.ChangeType(source, dest);
}
Run Code Online (Sandbox Code Playgroud)

编辑

更新后的问题有以下几行:

obj肯定实现了castTo

如果是这种情况,那么该Cast方法不需要存在.源object可以简单地分配给dynamic参考.

dynamic d = source;
Run Code Online (Sandbox Code Playgroud)

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

  • 漂亮的代码...但是为什么调用方法Convert?系统名称空间陷阱。称之为“ DynamicConvert”或类似名称。 (2认同)

rse*_*nna 31

这应该工作:

public static dynamic Cast(dynamic obj, Type castTo)
{
    return Convert.ChangeType(obj, castTo);
}
Run Code Online (Sandbox Code Playgroud)

编辑

我写了以下测试代码:

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

它类似于一种"类型转换"在PHP,JavaScript的或Python语言的一个发现(因为它也的转换价值所需的类型).我不知道这是不是一件好事,但它确实有效...... :-)

  • 是的,这不适用于实体类型(这是我的用例) (3认同)
  • 只因为String是IConvertible.您使用的类型必须使用IConvertible方法生成,因为该方法只进行适当的Convert.ToABCD()调用.因此,它仍限制您在引用类型之间进行转换的能力.字符串恰好是例外,因为IConvertible要求您实现ToString. (2认同)
  • @George Mauer:所以你的用例对我来说没有意义.正如@JaredPar的回答所解释的那样,对象是一个对象 - 如果您已经在使用它的动态引用,那么您应该能够毫无问题地访问其方法和/或属性.所以也许问题*是*你的用例...顺便说一句,这就是为什么我(错误地)假设你只是想为简单的类型值获得快速转换方法. (2认同)

Geo*_*uer 8

我到目前为止最好的:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 当```是`DerivedClass`的实例时,你似乎相信`(动态)(BaseClass)x`的行为可能与`(动态)(DerivedClass)x`不同.但这种差异应该从哪里来?该对象不记得曾经引用它的引用类型. (3认同)
  • 这对我来说没有意义.如何调用`DynamicCast(obj,typeof(Foo))`与`(动态)obj`有什么不同,除了在`obj`(具有***编译时**)的情况下你得到一个空引用*类型`对象`)恰好不是`Foo`?此外,约束`其中T:object`是无意义和不允许的. (2认同)
  • 这仍然没有意义。首先,您编写的“装箱”与将值类型(如结构)放入引用类型变量有关。您的“Professor”和“Person”示例必然涉及类,而不是结构。其次,如果 `Professor` ___overrides___ 该方法,虚拟调度将确保使用“最派生”的实现。即使发生了方法隐藏,上面的“DynamicCast”方法也没有帮助。在所有情况下,“DynamicCast(obj, typeof(Foo))”似乎等同于“(obj is Foo)”?(动态)obj:null`。只需使用“(动态)obj”即可。 (2认同)

jbt*_*ule 7

开源框架Dynamitey有一个静态方法,它使用DLR进行后期绑定,包括强制转换.

dynamic Cast(object obj, Type castTo){
    return Dynamic.InvokeConvert(obj, castTo, explict:true);
}
Run Code Online (Sandbox Code Playgroud)

这比Cast<T>使用反射调用的优势在于,这也适用于IDynamicMetaObjectProvider具有动态转换运算符的任何运算符,即.TryConvert onDynamicObject.


JRo*_*odd 7

我知道已经解决了这个问题,但是我使用了不同的方法,并认为可能值得分享。另外,我觉得我的方法可能会产生不必要的开销。但是,在我们观察到的负载下,我无法观察或计算出任何糟糕的事情。我一直在寻找有关此方法的有用反馈。

使用动力学的问题是您不能将任何函数直接附加到动态对象。您必须使用一些可以计算出您不想每次都分配的作业。

在计划这个简单的解决方案时,我研究了尝试重新键入相似对象时有效的中介机构。我发现二进制数组,字符串(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));
    }
}
Run Code Online (Sandbox Code Playgroud)

话虽如此,这适合我组合在一起的另一个实用程序,使我可以将任何对象变成动态对象。我知道我必须使用反射来正确地做到这一点:

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;
}
Run Code Online (Sandbox Code Playgroud)

我必须提供该功能。分配给动态类型变量的任意对象都不能转换为IDictionary,这会破坏ConvertDynamic函数。为了使用此功能链,必须为其提供动态的System.Dynamic.ExpandoObject或IDictionary <string,object>。