不使用泛型将类A转换为类B

本文关键字:转换 泛型 | 更新日期: 2023-09-27 18:14:01

我有两个彼此没有连接的类:

public class A
{
   public String Address {get;set}
}
public class B 
{
   public String Address {get;set}
}
List<A> addressList = DB.Addresses.GetAll();

当我做

List<B> addressListOther = addressList.Cast<B>().ToList();

输出为:

附加信息:无法将类型"A"的对象强制转换为类型"B"。

有什么办法吗?

不使用泛型将类A转换为类B

您可以使用Select()代替这种方式:

List<B> addressListOther = addressList.Select(a => new B { Address = a.Address}).ToList();

或者您可以覆盖B类中的explicit operator:

public static explicit operator B(A a)  // explicit A to B conversion operator
{
    return new B { Address = a.Address };
}

,然后:

List<B> addressListOther = aList.Select(a => (B)a).ToList();

这个异常的原因:

Cast将抛出InvalidCastException,因为它试图将A转换为object,然后将其转换为B:

A myA = ...;
object myObject = myA ;
B myB= (B)myObject; // Exception will be thrown here

这个异常的原因是,装箱值只能解装箱为与类型完全相同的变量。//


附加信息:

如果您感兴趣,下面是Cast<TResult>(this IEnumerable source)方法的实现:
public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
    IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
    if (typedSource != null) return typedSource;
    if (source == null) throw Error.ArgumentNull("source");
    return CastIterator<TResult>(source);
}
如您所见,它返回CastIterator:
static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
    foreach (object obj in source) yield return (TResult)obj;
}

看看上面的代码。它将使用foreach循环遍历源代码,并将所有项转换为object,然后转换为(TResult)

它们不能相互继承,所以你不能这样做。Cast<T>遍历集合,并尝试将元素强制转换为指定的类型。

如果你做以下事情,你将失败:

A a = new A { Address = "a"};
B b = (B)a; // Compile error of: Cannot convert type A to B

使用Select来投影新的B项目。

List<B> addressListOther = addressList.Select(a => new B { Address = a.Address}).ToList();

另一种方法是在A类中重写implicit operator:
public static implicit operator B(A a)
{
    return new B { Address = a.Address };
}

然后下面的代码将word:

List<A> aList = new List<A> { new A { Address = "a" } };
List<B> bList = aList.Select(a => (B)a).ToList();

对我来说最简单的方法是引入一个超类。

public class ClassWithAddress
{
    public string Address{get;set;}
}

然后你将从那个类中派生出每个类,并像这样删除address属性:

public class A : ClassWithAddress
{
}
public class B : ClassWithAddress
{
}

之后,你可以用超类ClassWithAddress做关于地址属性的列表操作。