【问题标题】:How do I avoid duplicate code while parsing two different objects from a file?如何在解析文件中的两个不同对象时避免重复代码?
【发布时间】:2019-10-17 22:23:35
【问题描述】:

我想解析一个如下所示的 csv 文件。 CSV 文件包含两种不同的类型:行星和小行星。这两种类型都有一些独特的属性。

我创建了一个 Planet 类和一个 Asteroid 类,它们都继承自抽象 SpaceObject 类。我创建了一个解析器类,它将我的 csv 文件解析为一个 SpaceObjects 列表。不幸的是,我的课程包含重复的代码,而这正是我要避免的。

我的代码:

switch (ReadStringFromCellBasedOnHeader("type"))
{
    case "Asteroid":
        var asteroid = new Asteroid();
        asteroid.Position = new Vector2D(ReadDoubleFromCellBasedOnHeader("x"), ReadDoubleFromCellBasedOnHeader("y"));
        asteroid.Speed = new Vector2D(ReadDoubleFromCellBasedOnHeader("vx"), ReadDoubleFromCellBasedOnHeader("vy"));
        asteroid.Radius = ReadDoubleFromCellBasedOnHeader("radius");
        asteroid.Color =
            (Color?)ColorConverter.ConvertFromString(ReadStringFromCellBasedOnHeader("color")) ?? Color.FromRgb(0, 0, 0);
        break;
    case "Planet":
        var planet = new Planet();
        planet.Name = ReadStringFromCellBasedOnHeader("name");
        planet.Position = new Vector2D(ReadDoubleFromCellBasedOnHeader("x"), ReadDoubleFromCellBasedOnHeader("y"));
        planet.Speed = new Vector2D(ReadDoubleFromCellBasedOnHeader("vx"), ReadDoubleFromCellBasedOnHeader("vy"));
        planet.Neighbours.AddRange(ReadStringFromCellBasedOnHeader("neighbours").Split(','));
        planet.Radius = ReadDoubleFromCellBasedOnHeader("radius");
        planet.Color =
            (Color?)ColorConverter.ConvertFromString(ReadStringFromCellBasedOnHeader("color")) ?? Color.FromRgb(0, 0, 0);
        break;
    default:
        throw new Exception("Unknown SpaceObject Type");
}

string ReadStringFromCellBasedOnHeader(string header)
{
    return fields[columnDictionary[header]];
}

double ReadDoubleFromCellBasedOnHeader(string header)
{
    return StringConverter.ToDouble(ReadStringFromCellBasedOnHeader(header));
}

正如您所见,我的 Planet 和 Asteroid 对象完全相同,除了 Planet 包含两个独特的属性(名称和邻居)。我在考虑使用 Factory 或 Builder 模式,但我不想创建一个有九个参数的函数。如何以优雅的方式避免重复代码?

【问题讨论】:

    标签: c# design-patterns


    【解决方案1】:

    你可以简单地把它们放在开关下面:

    SpaceObject spaceObject;
    
    switch (ReadStringFromCellBasedOnHeader("type"))
    {
        case "Asteroid":
            spaceObject = new Asteroid();
            break;
        case "Planet":
            var planet = new Planet();
            spaceObject = planet;
            planet.Name = ReadStringFromCellBasedOnHeader("name");
            planet.Neighbours.AddRange(ReadStringFromCellBasedOnHeader("neighbours").Split(','));
            break;
        default:
            throw new Exception("Unknown SpaceObject Type");
    }
    
    spaceObject.Position = new Vector2D(ReadDoubleFromCellBasedOnHeader("x"), ReadDoubleFromCellBasedOnHeader("y"));
    spaceObject.Speed = new Vector2D(ReadDoubleFromCellBasedOnHeader("vx"), ReadDoubleFromCellBasedOnHeader("vy"));
    spaceObject.Radius = ReadDoubleFromCellBasedOnHeader("radius");
    spaceObject.Color =
        (Color?)ColorConverter.ConvertFromString(ReadStringFromCellBasedOnHeader("color")) ?? Color.FromRgb(0, 0, 0);
    

    或者,您可以使用辅助函数:

    switch (ReadStringFromCellBasedOnHeader("type"))
    {
        case "Asteroid":
            var asteroid = new Asteroid();
            DeserializeCommon(asteroid);
            break;
        case "Planet":
            var planet = new Planet();
            DeserializeCommon(planet);
            planet.Name = ReadStringFromCellBasedOnHeader("name");
            planet.Neighbours.AddRange(ReadStringFromCellBasedOnHeader("neighbours").Split(','));
            break;
        default:
            throw new Exception("Unknown SpaceObject Type");
    }
    
    void DeserializeCommon(SpaceObject spaceObject)
    {
        spaceObject.Position = new Vector2D(ReadDoubleFromCellBasedOnHeader("x"), ReadDoubleFromCellBasedOnHeader("y"));
        spaceObject.Speed = new Vector2D(ReadDoubleFromCellBasedOnHeader("vx"), ReadDoubleFromCellBasedOnHeader("vy"));
        spaceObject.Radius = ReadDoubleFromCellBasedOnHeader("radius");
        spaceObject.Color =
            (Color?)ColorConverter.ConvertFromString(ReadStringFromCellBasedOnHeader("color")) ?? Color.FromRgb(0, 0, 0);.
    }
    

    【讨论】:

    • 感谢您的广泛回答!我的编译在spaceObject.Color = (Color?)ColorConverter.ConvertFromString(ReadStringFromCellBasedOnHeader("color")) ?? Color.FromRgb(0, 0, 0); 上抛出错误(令牌无效)我该如何解决这个问题?
    • @Frogical 请给出确切的错误信息?此代码是从您的问题中复制而来的。
    • System.FormatException: '令牌无效。'在我上面复制的那一行。
    • 哦,是运行时异常,不是编译器错误?我怀疑这是由于试图解析一个无法解析为颜色的值造成的。没有更多细节很难提供帮助,但这很可能也会影响您问题中的代码。
    • “灰色”,而不是“灰色”。 ColorConverter 识别“灰色”,但不识别“灰色”。
    【解决方案2】:

    通过将重复的代码移到开关外:

    SpaceObject spaceObject;
    switch (ReadStringFromCellBasedOnHeader("type"))
    {
        case "Asteroid":
            spaceObject = new Asteroid();
            break;
        case "Planet":
            var planet = new Planet()
            {
                Name = ReadStringFromCellBasedOnHeader("name"),
                Neighbours = new List<string>();    
            };
            planet.Neighbours.AddRange(
                 ReadStringFromCellBasedOnHeader("neighbours").Split(','));
            spaceObject = planet;
            break;
        default:
            throw new Exception("Unknown SpaceObject Type");
    }
    spaceObject.Position = new Vector2D(ReadDoubleFromCellBasedOnHeader("x"), ReadDoubleFromCellBasedOnHeader("y"));
    spaceObject.Speed = new Vector2D(ReadDoubleFromCellBasedOnHeader("vx"),ReadDoubleFromCellBasedOnHeader("vy"));
    spaceObject.Radius = ReadDoubleFromCellBasedOnHeader("radius");
    spaceObject.Color =
        (Color?) ColorConverter.ConvertFromString(ReadStringFromCellBasedOnHeader("color")) ?? Color.FromRgb(0, 0, 0);
    

    【讨论】:

    • 谢谢! Neighbors (in Planet) 是一个 List。所以我必须先初始化它。像这样:new List()。如何用邻居初始化 Planet 对象? (您当前的代码不起作用)
    • 我已经编辑了我的答案。但是请注意,理想情况下,Neighbours 应该在Planet 的构造函数中初始化。更好的是,该构造函数应该接受一个 IEnumerable 并且 Neighbours 应该作为 IReadOnlyList 类型的 get only 属性公开。
    猜你喜欢
    • 1970-01-01
    • 2020-01-23
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多