代码之家  ›  专栏  ›  技术社区  ›  Dinah SLaks

在两个对象上运行相同的代码

c#
  •  0
  • Dinah SLaks  · 技术社区  · 15 年前

    下面的细节无关紧要。重要的是模式。

    var stagingDbs = cleanupDbs(stagingServer.Databases);
    var prodDbs = cleanupDbs(prodServer.Databases);
    
    printDiff(stagingDbs, prodDbs, "Databases mis-matched");
    
    foreach (var db in stagingDbs.Intersect(prodDbs)) {
        var stagingDb = stagingServer.Databases[db];
        var prodDb = prodServer.Databases[db];
    
        var stagingTables = cleanupTables(stagingDb.Tables);
        var prodTables = cleanupTables(prodDb.Tables);
    
        printDiff(stagingTables, prodTables, "Tables mis-matched on " + db);
    
        foreach (var table in stagingTables.Intersect(prodTables)) {
            var stagingTable = stagingDb.Tables[table];
            var prodTable = prodDb.Tables[table];
    
            var matchedColumns = stagingColumns.Intersect(prodColumns);
    
            var stagingTableColumns = stagingTable.Columns
                .Cast<Column>()
                .Where(c => matchedColumns.Contains(c.Name))
                .Select(c => formatColumn(c));
            var prodTableColumns = prodTable.Columns
                .Cast<Column>()
                .Where(c => matchedColumns.Contains(c.Name))
                .Select(c => formatColumn(c));
            printDiff(stagingTableColumns, prodTableColumns,
                "Columns mis-matched");
        }
    }
    

    例如,我不想换这个

            var stagingTableColumns = stagingTable.Columns
                .Cast<Column>()
                .Where(c => matchedColumns.Contains(c.Name))
                .Select(c => formatColumn(c));
            var prodTableColumns = prodTable.Columns
                .Cast<Column>()
                .Where(c => matchedColumns.Contains(c.Name))
                .Select(c => formatColumn(c));
    

    带着这个

            var stagingTableColumns = doStuff(stagingTable, matchedColumns);
            var prodTableColumns = doStuff(prodTable, matchedColumns);
    

    因为我必须确保第一行的所有东西 stagingXyz 第二行是 prodXyz . 对于一行来说还不错,但是测试脚本非常庞大,而且只做过以下两件事之一:

    • foo(stagingXyz);foo(prodXyz);
    • 棒(stagingXyz,prodXyz);

    类似地,用数组中的这些项包装 doStuff[0]; doStuff[1]; 同样容易出错,只有0对1的错误更难一目了然。

    我考虑过制作两个容器对象(一个用于暂存,一个用于prod)并将这两个对象放在一个集合中,但我担心这会导致大量的小循环,很难维护。

    有没有什么方法可以简化它,使它仍然可读和可维护?

    2 回复  |  直到 15 年前
        1
  •  0
  •   twon33    15 年前

    你能生成你的测试脚本吗?输入的内容可能如下

    var %%AB%%Dbs = cleanupDbs(%%AB%%Server.Databases);
    printDiff(%%A%%Dbs, %%B%%Dbs, "Databases mis-matched");
    foreach (var db in %%A%%Dbs.Intersect(%%B%%Dbs)) {
    
        var %%AB%%Db = %%AB%%Server.Databases[db];
        var %%AB%%Tables = cleanupTables(%%AB%%Db.Tables);
    
        printDiff(%%A%%Tables, %%B%%Tables, "Tables mis-matched on " + db);
    
        ...
    }
    

    包含%%A B%%的行可能会扩展为同一行的两个副本,一个使用“A”替换,另一个使用“B”替换,其中,%%A%或%%B%本身可能会被替换。

        2
  •  0
  •   Ocelot20    15 年前

    编辑 -看了你的评论后,我现在看问题更清楚了。我认为问题更多的是一个大函数的清晰性,而不是想出一个时髦的方法来解决可读性问题。我想你越是把它分解成更小的函数,它就越清晰。

    如果主要功能被分解成这样:

    public void mainMethod(DB prodDB, DB stagingDB)
    {
        doPart1(prodDB, stagingDB);
        doPart2(prodDB, stagingDB);
    }
    

    ……每个部分都有很好的命名输入,比如:

    public void doPart1(DB prodDB, DB stagingDB)
    {
        // Code...    
    }
    

    当你让事情在一个越来越细的层次上工作时,事情就会变得清晰起来。任何在doPart1方法中工作的人只需要关心它的少量代码,任何在main部分工作的人都不应该有太多东西要检查。我知道这听起来是不是过于简单化了,但听起来你是在试图解决一个问题,如果代码被正确地分解,这个问题就不应该存在。

    如果有一个方法是如此庞大和不可读,以致于另一个开发人员无法找出只有两个变量的情况,那么就有一个不同的问题。