【问题标题】:Cast class A to class B without generics在没有泛型的情况下将 A 类转换为 B 类
【发布时间】:2016-10-20 07:50:31
【问题描述】:

我有两个彼此没有联系的班级:

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”类型。

知道如何解决这个问题吗?

【问题讨论】:

  • 你有什么想法?显然,当它们彼此不相关时,您不能将一种类型转换为另一种类型。您可以将它们更改为从同一接口继承(并强制转换为该接口)或手动将属性从一个复制到另一个。
  • 您需要循环列表并将一个类属性分配给另一个类属性。
  • 仅仅因为两个类具有相同的属性并不意味着它们在任何方面、形状或形式上都相关。 C# 将此类类视为完全不同的事物。如果你真的想把 A 变成 B 只是因为它们具有相同的属性,那么你不是在寻找转换而是在寻找映射。

标签: c# .net linq casting


【解决方案1】:

您可以使用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&lt;TResult&gt;(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)

【讨论】:

  • 很好的解释 :) 得到了我的支持。只有 - 你提到的第一种方法不起作用 - 看我的例子
  • 是的,您需要更正您的第一个示例。 .Select(x =&gt; (B)x) 正在做 .Cast&lt;B&gt;() 所做的事情,我们知道这是失败的。你不能投(B)A
  • @Liam 谢谢。其实我忘了说明他必须实现显式转换操作符。
  • @GiladGreen :) 如果您在 18 分钟前注意到我对我的回答的评论...))
  • @GiladGreen 我是否设法解释了自己?我不想陷入如此困难的境地。 :( 实际上,我正在工作。我正在编辑我的答案,但后来我的 PM 打电话给我。所以,我无法完成我的编辑。现在可以了吗?
【解决方案2】:

它们不会相互继承,所以你不能这样做。 Cast&lt;T&gt; 遍历集合并尝试将项目转换为指定的类型。

如果您执行以下操作,您将失败0:

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 };
}

然后下面的代码会写一句话:

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

【讨论】:

    【解决方案3】:

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

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

    然后您将从该类派生每个类并删除地址属性,如下所示:

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

    之后,您可以使用超类ClassWithAddress 对地址属性进行列表操作。

    【讨论】:

      猜你喜欢
      • 2022-11-07
      • 1970-01-01
      • 1970-01-01
      • 2019-11-21
      • 2017-03-11
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      相关资源
      最近更新 更多