繁体   English   中英

C#Dynamics:Convert.ChangeType与Cast

[英]C# Dynamics: Convert.ChangeType versus Cast

有人可以解释为什么在使用Convert.ChangeType时,将动态对象作为类返回该类会返回动态对象,特别是在运行时吗? 例如:

 dynamic dObject = new SomeClass();
 var dTest1 = dObject as SomeClass;                           // returns SomeClass
 var dTest2 = Convert.ChangeType(dObject, typeof(SomeClass)); // returns dynamic

更广泛的问题:我有一系列辅助类来实现通用接口。 我需要将这些类的列表传递给其他对象; 但是不同的帮助器类对泛型参数使用不同的类型,所以我不能直接传递辅助类的列表:

interface IHelper<T>
{
    IEnumerable<T> Foo();
}
var HelperList = new List<IHelper<T>> // Can't do this because T varies from helper to helper!

所以我认为我可以通过创建一个包含辅助类和泛型类型的容器类来伪造运行时,但是利用了动态:

class ContainerClass
{
    IHelper<dynamic> HelperClass;
    Type dType;                      // Specifies the type for the dynamic object
}

现在我可以创建并传递一个ContainerClass列表。 所有处理工作都很好,直到我需要将Foo()的结果分配回目标IEnumerables,此时我得到运行时错误,说明类型对象无法转换为这样的具体类,即使未装箱的对象类型匹配那些要求。 如果我尝试上面的dTest2中的类似语法,运行时仍然无法找出“转换”。

我意识到这可能是滥用动态和糟糕的编程习惯来启动的。 如果我能找到一个解决方案,我当然会使用不同的解决方案,但是现在我要么需要做这个工作,要么选择不那么雄心勃勃的东西。

在执行时,真的没有dynamic

但是,对Convert.ChangeType的调用是提供dynamic值作为参数。 使用dynamic参数的任何方法调用都被视为具有dynamic的返回值,因为编译器在执行时间之前不知道实际签名是什么。

但是,如果使用强制转换, isas表达式,或构造函数调用,则结果只有一种类型 - 这就是表达式的类型。

至于你更广泛的问题 - 我不清楚使用dynamic会特别有助于你。 您可能希望为IHelper<T>声明一个基本接口 - 一个非泛型接口,它只用于实际的IHelper<T>实例。 然后你可以得到一个List<IHelper> ,其中每个元素实际上是一些TIHelper<T> ,但是T在实例之间变化。 这里并不真正需要 IHelper接口,但如果你的IHelper<T>接口确实包含其他不使用T成员,那么可以将它们移动到IHelper 然而,仅仅为了清晰起见可能是有用的。

现在,当你需要使用特定的IHelper那么动态类型可以简单地是有用的。 您可以声明一个泛型方法,并让动态类型在执行时找出类型参数。 例如:

private readonly IList<IHelper> helpers;

...

public void UseHelpers()
{
    foreach (dynamic helper in helpers)
    {
        UseHelper(helper); // Figures out type arguments itself
    }
}

private void UseHelper<T>(IHelper<T> helper)
{
    // Now you're in a generic method, so can use T appropriately
}

根据Jon Skeet的回答,我认为你可以做一些非常有趣的事情并避免使用动态关键字,因为它会影响性能。

使用IHelper<T> : IHelper 现在,您可以将帮助程序存储到List<IHelper> 现在你可以通过将类型maping到泛型方法来调用Foo方法。

public IEnumerable<T> UseHelper<T> (IHelper<T> helper)
{

}

delegate IEnumerable<object> UseHelperDelegate(IHelper helper)
Dictionary<Type, UseHelperDelegate> helpersMap;

helpersMap.Add(typeof(int), UseHelper<int>); // Add others if you want

public IEnmerable<object> UseHelperWithMap(IHelper helper)
{
    Type helperType = helper.GetType();
    IEnumerable<object> retValue;
    if (helpersMap.Contains(helperType))
    {
         retValue = helpersMap[helperType](helper);
    }
    else // if the type is not maped use DLR
    {
         dynamic dynamicHelper = helper;
         retValue = UseHelper(dynamicHelper)
         // I wonder if this can actually be added to the map here
         // to improve performance when the same type is called again.
    }
}

注意:您可以投IEnumerable<SomeClass>IEnumerable<object>UseHelper<SomeClass>UsehelperDelegate因为协变和逆变

编辑:事实证明,你可以从通用创建一个新的具体功能,并将其添加到地图。 这样就可以避免使用dynamic

var useHelperGeneric = this.GetType().GetMethods().FirstOrDefault(
               m=> m.IsGenericMethod && m.Name == "UseHelper");
var useHelper = useHelperGeneric.MakeGenericMethod(new Type[] { helper.GetType() });
var newFunction = (UserHelperDelegate)useHelper.MakeDelegate(typeof(UseHelperDelegate));

helpersMap.Add(helper.GetType(), newFunction);

newFunction(helper);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM