【问题标题】:Dynamic casting to a generic type动态转换为泛型类型
【发布时间】:2014-02-07 10:40:35
【问题描述】:

我正在尝试访问 System.Activities.Statements.Switch 对象的 Cases.Values 属性。问题是我不能在运行时将 Activity 对象转换为 Switch<> 类型(派生自它)。

var switchType = activity.GetType();
bool isSwitch = (switchType.IsGenericType && switchType.GetGenericTypeDefinition() == typeof(Switch<>));

if (isSwitch)
{
    Type[] genericArgumentTypes = switchType.GetGenericArguments();
    if (genericArgumentTypes.Length > 0)
    {
        var switchStatement = (Switch<genericArgumentTypes[0]>) activity;  //that's incorrect
        foreach (var aCase in switchStatement.Cases.Values)
        {
            ProcessActivity(aCase, dataSets, context);
        }
    }
}

还有,

dynamic switchStatement = activity;
foreach (var aCase in switchStatement.Cases.Values)
{
    ProcessActivity(aCase, dataSets, context);
}

抛出一个错误,该属性不存在,而调试器显示它不正确。 T 与我无关 - 我只需要 Cases 集合。

编辑

实际上,我找到了比我设置为答案的更清洁的解决方案。

dynamic switchStatement = activity;
var cases = switchStatement.Cases as IEnumerable;
if (cases != null)
{
    foreach (dynamic aCase in cases)
    {
        ProcessActivity(aCase.Value);
    }
}

【问题讨论】:

标签: c# generics dynamic casting


【解决方案1】:

你不能。

但不是你的循环,而是:

var process = typeof(CurrentHelperClass).GetMethod("ProcessSwitch`1").MakeGenericMethod(typeof(genericArgumentTypes[0]));
 process.Invoke(null,new object[]{activity});

并在同一个类中定义一个新方法:

static void ProcessSwitch<T>(Switch<T> switchStatement)
{
    foreach (var aCase in switchStatement.Cases.Values)
    {
        ProcessActivity(aCase, dataSets, context);
    }
}

【讨论】:

  • Switch 是 System.Activities 命名空间的一部分。如何强制库类实现接口?
  • 哦,对了,我没有意识到这一点。您是自己实例化课程吗?如果是,您可以定义一个类 MySwitch : Switch, ISwitch。如果不是,我会提出一个新的答案(稍微复杂一点)
  • 没有。 Switch&lt;&gt; 是工作流中的一个节点。我正在审查它的每个节点(活动),我无法修改使用的活动类型。
  • 有什么方法可以在静态方法中做到这一点? :) 因为我基本上是在帮助类中使用它..
  • @Tarec 实际上它不应该是 "ProcessSwitch1", the problem is GetMethod` 默认只查找公共方法。使用GetMethod("ProcessSwitch", BindingFlags.NonPublic | BindingFlags.Static)。我认为这是最干净的解决方案,因为动态查找仅限于您的仅限自己的班级。
【解决方案2】:
var switchType = activity.GetType();
var prop = switchType.GetProperty("Cases", System.Reflection.BindingFlags.Public 
            | System.Reflection.BindingFlags.Instance); //move it outside of the method and use the same property for every time you call the method since it's performance expansive.
bool isSwitch = (switchType.IsGenericType && switchType.GetGenericTypeDefinition() == typeof(Switch<>));

if (isSwitch)
{
        IEnumerable dictionary = prop.GetValue(activity,null) as IDictionary;
        foreach (var item in dictionary.Values)
        {
            ProcessActivity(item, dataSets, context);
        }
}

【讨论】:

  • 谢谢。但是,我在字典对象分配上遇到 Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true. 异常。
  • 已编辑,现在可以使用了。您只需要动态使用GetType() 对您拥有的属性执行GetValue() 方法
  • 不幸的是,如果将 GetValue 转换为 IDictionary,则返回 null。如果我不强制转换并将其用作动态对象,我将获得字典对象,但同样 - 我将无法获得 Values 属性。
  • 编辑器使用 ienumerable 重试
  • 这个对象是 keyvaluepair 你可以对它使用 GetProperty 和 GetValue 来获取值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多