微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

直接转换数组或使用 System.Linq.Cast 有什么区别?

如何解决直接转换数组或使用 System.Linq.Cast 有什么区别?

假设我有 2 个类,AB,并且 B 可以转换为 A。我声明了一个名为 B[] 的类型为 b 的数组。那么如果我想将 b 转换为 A[](A[])bb.Cast<A>() 之间有什么区别?

解决方法

.Cast<T> 来自 Linq。它将枚举将每个项目转换为 T 的集合并创建一个新的序列。另一个是显式转换,告诉编译器您希望以该类型访问原始类型。

,

这是两种不同的东西。

语言转换

(A[])bb 强制转换为 A[] 类型,如果 b 不是 A[] 类型,则不会在运行时编译或抛出异常。

以双精度和整数的情况为例:

var array = new object[2];

array[0] = 10.2;
array[1] = 20.8;

var casted = (int[])array; // does not compile here,// or throw an exception at runtime if types mismatch

这里我们只是将一个类型转换为另一个类型,无论它们是什么,集合与否。

Casting and type conversions (C# Programming Guide)

Linq Cast

Cast<TResult>IEnumerable 的每个项目转换为 TResult

这只是一个已经编写的 LINQ 循环,使我们的生活更轻松,盒装值。

Enumerable.Cast(IEnumerable) Method

将 IEnumerable 的元素转换为指定类型。

来自source code

static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source)
{
  foreach (object obj in source) yield return (TResult)obj;
}

因此,此方法可用于从 RowsDataGridView 之类的集合或任何类似的“简化”集合(例如 {{1} 中的 Items } 或 ListBox

这意味着项目的类型必须是 ComboBox 或祖先的类型。

示例

TResult

注意

由于yielding,var array = new object[2]; array[0] = 10.2; array[1] = 20.8; var converted = array.Cast<int>(); // compiles but will not work // and throw an InvalidCastException 方法被延迟,所以我们只有在执行时才能得到结果,例如使用Castforeach

Deferred Execution of LINQ Query

Deferred Vs Immediate Query Execution in LINQ

Deferred execution and lazy evaluation

解决样本问题的替代方法

因此要转换数组,我们可以使用直接转换,例如使用 ToListforeach

Select

使用扩展方法

var converted = array.Select(v => (int)v).ToArray(); // get int[]

Console.WriteLine(string.Join(Environment.NewLine,converted));

> 10
> 20

还有 static public class EnumerableHelper { static public IEnumerable<TResult> Cast<TSource,TResult>(this IEnumerable<TSource> source) where TSource : IConvertible { foreach ( TSource obj in source ) yield return (TResult)Convert.ChangeType(obj,typeof(TResult)); } } var converted = array.Cast<double,int>(); > 10 > 21 以避免数字问题,以及避免四舍五入的格式化程序。

,

你的两个例子虽然不同,但都是无效的。

您不能将一种对象类型的数组转换为另一种对象类型,即使它们之间存在转换运算符(显式或隐式)。编译器正确地阻止了这种强制转换。这条规则的例外是如果存在继承关系;由于数组协方差,您可以向下转换为基本类型(对于引用类型)。以下工作:

class A {} 
class B : A {} 

B[] bs = new[] { new B() };
A[] result = (A[])bs; // valid

SharpLab

同样的原则适用于 LINQ 中的 Cast<T> 方法——除非类型匹配,否则将在运行时枚举时抛出异常。下面的答案是错误的。例如,您不能将 Cast 数组设为 doubleint。当然,如果您不枚举结果(例如在示例中),则不会发生异常。但是,在实际枚举 (foreach,ToList,ToArray) 时,将抛出 InvalidCastException

var array = new double[2];

array[0] = 10;
array[1] = 20;

var temp = array.Cast<int>(); // OK,not enumerated 
var converted = temp.ToList(); // bam! InvalidCastException 

注意 temp 变量——在下面的答案中,由于 LINQ 的延迟执行,它不会抛出。一旦你枚举它,它就会失败。见SharpLab

Cast 方法旨在弥补与预泛型集合之间的差距,其中值在内部存储为 object 数组,而集合本身仅实现 IEnumerableCast 允许转换为 IEnumerable<T>,但是除了从 object 到原始类型之外,不允许进行任何强制转换/转换。

对于结构体,这是显而易见的——装箱的 double 只能拆箱为 double;它不能拆箱为 int。以简单的非数组情况为例:

double d = 1.5;
object o = d;
int iOk = (int)(double)o; // ok
int iBad = (int)o; // fails

SharpLab

那么,Cast<int> 将失败是有道理的,因为该方法仅将单个强制转换插入到 int,并且不是double 的中间强制转换否则将需要。

对于类,同样 Cast 只会插入直接转换。该方法是通用的,不/不能考虑任何用户定义的运算符。因此,当您说“有两个可以相互转换的类”时,这仍然无关紧要。换句话说,以下将失败:

class A {} 
class B {
    public static implicit operator A(B b) => new A();
} 

B[] bs = new[] { new B() };
var temp = bs.Cast<A>(); // OK,not yet enumerated
A[] result = temp.ToArray(); // throws InvalidCastException 

SharpLab

同样(如上),这条规则的例外是两个类之间是否存在继承关系。你可以从一个到另一个:

class A {} 
class B : A {} 

B[] bs = new[] { new B() };
A[] result = bs.Cast<A>().ToArray(); // valid

SharpLab

另一种选择是使用 LINQ 的 Select 来投影您的原始集合,应用您想要的转换运算符:

class A {} 
class B {
    public static implicit operator A(B b) => new A();
} 

B[] bs = new[] { new B() };
A[] result = bs.Select(b => (A)b).ToArray(); // valid! 

SharpLab。这也适用于 double/int

var array = new double[] { 10.2,20.4 };
int[] result = array.Select(d => (int)d).ToArray();

SharpLab

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。