【问题标题】:Unable to cast object of type 'DAL Class' to type 'BLL Class'无法将“DAL Class”类型的对象转换为“BLL Class”类型
【发布时间】:2016-01-14 17:47:18
【问题描述】:

我在将 DAL 级类的结果“继承”到具有相同定义的 BLL 类时遇到问题。

错误:“无法将'DeserializedGame'类型的对象转换为'DeserializedGameBLL'类型。”

//DAL Classes
public class GameCollection{
    public List<DeserializedGame> Games { get; set; }
    public int RefreshInterval { get; set; }
    public string CurrentDate { get; set; }
    public string NextDate { get; set; }
    public string PrevDate { get; set; }
}

public class DeserializedGame
{
    public string Atcommon { get; set; }
    public string Canationalbroadcasts { get; set; }
    public string Ata { get; set; }
    public bool Rl { get; set; }
    public int Atsog { get; set; }
    public string Bs { get; set; }
    public string Htcommon { get; set; }
    public int Id { get; set; }
    public string Atn { get; set; }
    public int Hts { get; set; }
    public string Atc { get; set; }
    public string Htn { get; set; }
    public string Usnationalbroadcasts { get; set; }
    public bool Gcl { get; set; }
    public string Hta { get; set; }
    public int? Ats { get; set; }
    public string Htc { get; set; }
    public int Htsog { get; set; }
    public string Bsc { get; set; }
    public int Gs { get; set; }
    public bool Gcll { get; set; }
}

//BLL Classes
public class GameCollectionBLL : IEnumerable
{
    public List<DeserializedGame> Games { get; set; }
    public int RefreshInterval { get; set; }
    public string CurrentDate { get; set; }
    public string NextDate { get; set; }
    public string PrevDate { get; set; }

    public GameCollectionBLL(List<DeserializedGame> gameList, int refreshInterval, string currentDate,
        string nextDate, string previousDate)
    {
        this.Games = gameList;
        this.RefreshInterval = refreshInterval;
        this.CurrentDate = currentDate;
        this.NextDate = nextDate;
        this.PrevDate = previousDate;
    }

    public IEnumerator GetEnumerator()
    {
        return (Games as IEnumerable).GetEnumerator();
    }
}

public class DeserializedGameBLL : BaseSeasonSchedule
{
    public string Atcommon { get; set; }
    public string Canationalbroadcasts { get; set; }
    public string Ata { get; set; }
    public bool Rl { get; set; }
    public int Atsog { get; set; }
    public string Bs { get; set; }
    public string Htcommon { get; set; }
    public int Id { get; set; }
    public string Atn { get; set; }
    public int Hts { get; set; }
    public string Atc { get; set; }
    public string Htn { get; set; }
    public string Usnationalbroadcasts { get; set; }
    public bool Gcl { get; set; }
    public string Hta { get; set; }
    public int? Ats { get; set; }
    public string Htc { get; set; }
    public int Htsog { get; set; }
    public string Bsc { get; set; }
    public int Gs { get; set; }
    public bool Gcll { get; set; }
}

public abstract class BaseSeasonSchedule
{
    public int GameID { get; set; }
    public DateTime GameDate { get; set; }
}

//UI usage
public partial class Form1 : Form
{
    private SeasonSheduleBLL objSeasonSchedule = new SeasonSheduleBLL();

    private void button1_Click(object sender, EventArgs e)
    {
            GameCollectionBLL gameDay = objSeasonSchedule.GetGameCollection(json_string);

            foreach (DeserializedGameBLL game in gameDay)  //error occurs here when referencing the DeserialzedGameBLL
                    {
                        // do stuff here
                    }
    }
}

我需要做些什么才能使我的 DeserialzedGame 集合正常工作?

我查看了this question(并尝试遵循原始帖子中的@Measuring 建议)。我已经考虑过(但仍然没有消除using DTO's,但我不确定如何正确使用它们)。

如果这属于 Code Review 部分,我会很乐意在那里发帖,但我认为可能有足够多的人正在经历与我一样的挫败感。

【问题讨论】:

  • 使用 Automapper 或其他库在图层中的对象之间进行映射。
  • 错误告诉你不能在两个不相关的类型之间隐式转换。您必须创建目标类型的新实例并将其属性设置为与源类型匹配。但是......为什么你首先有两个相同的类型?只需在整个系统中使用其中一个并删除另一个。
  • @David 假设您的建议是 DTO 的全部内容是否正确?
  • @Kulstad:嗯,您的对象已经 DTO。所以我真的不知道你在那里问什么。但关键是你真的不需要完全相同的对象
  • @David 我认为这是我开始感觉自己在编写体重级别之外的代码的地方。我知道你在告诉我什么,我只是不知道如何实现它。

标签: c#


【解决方案1】:

错误只是告诉您不能在两种不相关的类型之间进行隐式转换。仅仅因为它们看起来相同并不意味着它们是同一类型。要纠正此问题,您必须创建目标类型的实例并将所有数据从源对象复制到目标对象。 (或者使用像 Automapper 这样的库来做同样的事情。)

然而,这确实引出了一个问题……为什么你一开始就有相同的类型?

[基于上述问题的 cmets...] 看来您有这样的架构:

  • 应用层引用业务层。
  • 业务层引用数据层。
  • 数据层不引用任何内容。

所以发生的事情是:

  • 数据层有一个类型,因此它可以实现数据库中的数据。
  • 业务层从数据层获取该对象。
  • 应用层需要那个对象,但是不能引用数据层。所以业务层需要将数据层对象转换为应用层可以接收的业务层对象。

光是说说就让人头疼:)

相反,考虑稍微修改一下架构:

  • 通用库包含 DTO(可能还有接口和其他通用类型),但没有有意义的逻辑,也没有任何引用。
  • 应用层引用业务层和通用库。
  • 业务层引用数据层和通用库。
  • 数据层引用公共库。

现在数据层返回的对象无需修改即可一直到达应用层,因为每个层都理解该类型。

这并不是说这种设置是理想的。在许多情况下,我什至会争辩说,这种“通用 DTO”方法可以很快成为一种反模式,并且不能很好地替代适当的域驱动架构。 但是,对于这些事情,我一直是个纯粹主义者。我的论点取决于业务层不引用任何内容而数据层引用业务层的想法。除非您熟悉依赖倒置模式和技术,否则这对您来说会很困难。

在这种简单的 3 层垂直架构的简单情况下,拥有一个通用库可以非常方便地避免这个确切的问题。

【讨论】:

  • 非常感谢您在我的原始帖子中提供的 cmets 以及此澄清。我已经实现了你的建议,效果很好。
【解决方案2】:

您可以使用诸如Automapper 之类的库,也可以使用explicit 关键字自己执行此操作。

public class DeserializedGame
{
    public string Atcommon { get; set; }
    public string Canationalbroadcasts { get; set; }
    public string Ata { get; set; }
    public bool Rl { get; set; }
    public int Atsog { get; set; }
    public string Bs { get; set; }
    public string Htcommon { get; set; }
    public int Id { get; set; }
    public string Atn { get; set; }
    public int Hts { get; set; }
    public string Atc { get; set; }
    public string Htn { get; set; }
    public string Usnationalbroadcasts { get; set; }
    public bool Gcl { get; set; }
    public string Hta { get; set; }
    public int? Ats { get; set; }
    public string Htc { get; set; }
    public int Htsog { get; set; }
    public string Bsc { get; set; }
    public int Gs { get; set; }
    public bool Gcll { get; set; }
    public static implicit operator DeserializedGameBLL(DeserializedGame game)
   {
       return new DeserializedGameBLL()
       {
           pubAtcommon = pubAtcommon,
           Canationalbroadcasts= Canationalbroadcasts,
           Ata = Ata ,
           Rl = Rl ,
           Atsog = Atsog ,
           Bs = Bs ,
           Htcommon = Htcommon ,
           Id = Id ,
           Atn =Atn ,
           Hts =Hts ,
           Atc =Atc ,
           Htn =Htn,
           Usnationalbroadcasts =Usnationalbroadcasts,
           Gcl =Gcl,
           Hta =Hta,
           Ats =Ats,
           Htc =Htc,
           Htsog = Htsog,
           Bsc = Bsc,
           Gs = Gs,
           Gcll = Gcll 
        };
    }
}

你可以这样使用:

DeserializedGame b = new DeserializedGame();
DeserializedGameBLL c = b;

您也可以使用explicit 运算符并进行设置,这样如果您不想要自动转换,也不需要强制转换。

【讨论】:

  • 不会将'public static implicit operator 添加到 DAL 中的 DeserializedGame 类中,从而需要 DAL 类了解 BLL 类?
  • @Kulstad 是的,它会,但它与使用 Automapper 或类似库没有任何不同
猜你喜欢
  • 2020-02-10
  • 1970-01-01
  • 2021-01-15
  • 2016-04-02
  • 2017-04-25
  • 1970-01-01
  • 2021-07-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多