【问题标题】:Generic types cannot Cast, although IsAssignableFrom泛型类型不能转换,尽管 IsAssignableFrom
【发布时间】:2017-04-14 21:47:34
【问题描述】:

我有一个通用的 QueryProvider,可以根据请求提供某种类型的数据(序列)。

在提供数据之前,我检查请求的类型 IsAssignableFrom 是否是我可以提供的类型。

编译器对从IEnumerable<TData> 转换为IEnumerable<TResult> 感到满意,但它抱怨将TData 转换为TResult

class MyClass<TData>
{
    private IEnumerable<TData> GetSequence() {return Enumerable.Empty<TData>(); } 

    private TData GetSingleValue() { return default(TData); }

    public TResult GetResult<TResult>()
    {
        TResult result;
        if (typeof(TResult).IsAssignableFrom(typeof(IEnumerable<TData>)))
        {   // we can Assign IEnumerable<TData> to TResult
            IEnumerable<TData> data = GetSequence();
            result = (TResult)data;
        }
        else if (typeof(TResult).IsAssignableFrom(typeof(TData)))
        {   // we can assing TData to TResult:
            TData data = GetSingleValue();
            result = (TResult)data;

编译器错误 CS0030 无法将类型“TData”转换为“TResult”

        }
        else
            throw new InvalidOperationException("Can't provide data");
        return result;
    }
}

为什么转换为IEnumerable&lt;TData&gt;IEnumerable&lt;TResult&gt; 没有问题,但不能将TData 转换为TResult?

在一些 cmets 之后添加 事实上,IsAssignable 与问题无关。让我困惑的是IEnumerable转换没有问题,而直接转换是。

where 子句当然解决了这个问题,但这只是改变了一个问题:为什么IEnumerable 可以不使用 where 子句,为什么直接转换需要 where 子句:

IEnumerable<TData> items = ...;
TData item = items.FirstOrDefault();
TResult result1 = (IEnumerable<TResult>) items;    // compile time OK
TResult result2 = (TResult) item;                  // compile time problem



var obj = (object)item;
TResult result3 = (TResult) obj;                   // compile time OK;

如果编译器不能证明我的显式转换是不正确的,那它会给我带来怀疑的好处吗?

【问题讨论】:

  • 可能是从单例 (typeof(TData)) 转换为 IEnumerable 的问题。
  • 通用代码必须是类型安全的,编译器不能保证强制转换总是可行的。运行时测试不足以说服它。您必须自己提供该保证并添加约束where TResult : TData

标签: c# casting


【解决方案1】:

您的问题和您的代码没有对齐。您的代码没有尝试将TData 转换为TResult。它正在尝试将IEnumerable&lt;TData&gt; 转换为`TResult。

如果IEnumerable&lt;TData&gt;IEnumerable&lt;TResult&gt; 有效。 IEnumerable&lt;TData&gt;TResult 不会。

【讨论】:

    【解决方案2】:

    IsAssignableFrom 并没有真正链接到任何这些,它是运行时检查,而编译器所做的类型检查是编译时检查。

    它不允许您将 TData 转换为 TResult,因为它无法验证该转换,因为这两种类型之间没有定义任何关系。同时 IEnumerable 是一个接口,因此转换可能是有效的 - 转换接口与转换具体类型参数不同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-24
      相关资源
      最近更新 更多