【问题标题】:C# Refactoring the same action with different details using design patternsC# 使用设计模式重构具有不同细节的相同操作
【发布时间】:2013-04-25 04:46:36
【问题描述】:

我试图找到重构代码的方法,但不知道该怎么做。

例如,我们有几个类

class A {
     string name;
     int year;
}

class B {
      long id;
      string code; 
      DateTime currentTime;
}

class C {
      string lastname;
      DateTime currentDate; 
}

然后我需要返回这些类 List、List、List 的对象列表并将它们转换为 Object[][]。

对于每次转化我都做同样的事情

private Object[][] converAListToObjectArray(List<A> dataList)
        {
            long countRecords = dataList.Count();
            const int countProperty = 2;
            var arrayRes = new object[countRecords][];

            for (int i = 0; i < countRecords; i++)
            {
                var arrayObjProperty = new object[countProperty];
                arrayObjProperty[0] = dataList[i].Name;
                arrayObjProperty[1] = dataList[i].Year;

                arrayRes[i] = arrayObjProperty;
            }
            return arrayRes;
        }

private Object[][] converBListToObjectArray(List<B> dataList)
        {
            long countRecords = dataList.Count();
            const int countProperty = 3;
            var arrayRes = new object[countRecords][];

            for (int i = 0; i < countRecords; i++)
            {
                var arrayObjProperty = new object[countProperty];
                arrayObjProperty[0] = dataList[i].Id;
                arrayObjProperty[1] = dataList[i].Code;
                arrayObjProperty[2] = dataList[i].CurrentTime; 

                arrayRes[i] = arrayObjProperty;
            }
            return arrayRes;
        }

是否可以使用某种设计模式来分离这种转换?

【问题讨论】:

  • 不清楚你想在这里完成什么..你想得到一个通用的,将列表转换为二维数组函数吗?
  • @Sayse 我尝试创建将任何对象列表转换为二维数组的统一函数
  • 你为什么要这样做?
  • 不过,这确实是一件很奇怪的事情。你在什么情况下以这种方式穿梭于物体周围?为什么泛型在这里不起作用?
  • 如果这真的只适用于 Excel,并且您使用的是 Excel 2007 或更高版本,请阅读Office Open XML Formats: Inserting Values into Excel 2007 Cells

标签: c# design-patterns refactoring template-method-pattern


【解决方案1】:

您可以编写一个通用函数,该函数使用反射来获取每个对象的字段名称和值。您需要决定它是适用于公共领域还是私有领域。下面的示例同时获取公共和私有字段:

static object[][] ConvertToObjectArray<T>(IList<T> objects)
{
    var fields = (from fieldInfo in typeof(T).GetFields(
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
                  orderby fieldInfo.Name
                  select fieldInfo).ToArray();

    object[][] table = new object[objects.Count][];
    for (int i = 0; i < table.Length; i++)
    {
        table[i] = (from fieldInfo in fields
                    select fieldInfo.GetValue(objects[i])).ToArray();
    }
    return table;
}

【讨论】:

  • 这是我的想法,但我真的很怀疑这里的用例是什么。
【解决方案2】:

您可以使用一个动作并执行以下操作:-

class Program
{
    // Your new function, (doesn't have to be static; just did it for the demo)
    // If you really really want to return object[][] still,
    // You'll need to pass an index to foo as well
    private static List<IList<object>> convert<T>(IList<T> dataList, Action<IList<object>, T> foo)
    {
        var arrayRes = new List<IList<object>>();

        foreach (var item in dataList)
        {
            var arrayObjProperty = new List<object>();
            foo(arrayObjProperty, item);

            arrayRes.Add(arrayObjProperty);
        }
        return arrayRes;
    }

    // The rest is just calling the function with two examples
    static void Main(string[] args)
    {
        var bar = new List<A>();
        bar.Add(new A() { name = "qux", year = 2013 });

        var objects1 = convert(bar, (a, b) =>
        {
            a.Add(b.name);
            a.Add(b.year);
        });

        var baz = new List<B>();
        baz.Add(new B() { code = "qux", id = 2013 });

        var objects2 = convert(baz, (a, b) =>
        {
            a.Add(b.code);
            a.Add(b.id);
        });
    }
}

您可以将其复制到您的 IDE 中进行播放,看看它是如何工作的。基本上,这使用泛型,然后是一个动作,以允许您在传递给方法的 lambda 中执行每次唯一不同的部分。

【讨论】:

    【解决方案3】:

    您可以简化并使用类似的东西 - 例如对于B...

    List<B> list = new List<B> 
    {
        new B{ id = 1, code = "", currentTime = DateTime.Now},
        new B{ id = 1, code = "", currentTime = DateTime.Now},
        new B{ id = 1, code = "", currentTime = DateTime.Now},
    };
    
    var array = list.Select(x => new object[] { x.id, x.code, x.currentTime }).ToArray();
    

    【讨论】:

      【解决方案4】:

      您的Object[][] 结构在我看来有点不寻常。你知道列表有一个Cast 方法吗?

      您可以执行以下操作:

      List<A> foo = new List<A> ();
      
      // initialize foo here
      var bar = foo.Cast<Object>().ToArray();
      

      这将为您提供一个字段名称完整的对象数组。如果您绝对需要将字段作为数组元素(为什么要这样做),您可以为每个类添加一个 ToObject 方法:

      class A
      {
          public string name;
          public int year;
          public Object[] ToObject()
          {
              return new Object[] {name, year};
          }
      }
      
      
          List<A> foo = new List<A>
          {
              new A{name="reacher",year=2013},
              new A{name="Ray",year=2013}
          }; 
          var bux = foo.Select(a => a.ToObject()).ToArray() ;
      

      【讨论】:

      • 我需要在 Excel 中填写数据范围
      • 这不是 Ray 的真正解决方案。 Ray 还希望将属性放入对象数组中。
      • 我倾向于不同意你的观点,马丁。第二个示例将允许 Ray 写 bux[0][0] 或等。所以这似乎满足了他的要求。你能帮我理解你为什么不这么认为吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多