萬用String Join使用IEnumerable Extension

  • 14588
  • 0
  • .Net
  • 2010-08-22

剛剛看到網友分享String.Join的小技巧,我就想到我前陣子,因為String.Join只能對String陣列操作,不能對集合如List、DataTable、IQueryable等類型操作,所以我自己就寫了一個Extension來方便自己,以便對集合可以是像String一樣使用Join。

 

剛剛看到網友分享String.Join的小技巧,我就想到我前陣子,因為String.Join只能對String陣列操作,不能對集合如List、DataTable、IQueryable等類型操作,所以我自己就寫了一個Extension來方便自己,以便對集合可以是像String一樣使用Join。

 

使用方式

IEnumerable source = null;
source.Join();
source.Join("PropertyName",",");
source.Join(separator: "|");

 

原始碼

下載 IterateExtension.cs

/// <summary>
/// 集合、陣列等反複物件的操作。
/// </summary>
public static class IterateExtension
{
/// <summary>
/// 將物件陳列組合成字串,使用物件的屬性名稱取得物件屬性值。
/// </summary>
/// <param name="source">可列舉來源</param>
/// <param name="propertyName">物件的屬性名稱</param>
/// <param name="separator">分隔字串</param>
/// <returns></returns>
public static string Join(this IEnumerable source, string propertyName = null, string separator = ",")
{
    if (source == null)
    {
        return null;
    }
 
    bool nullProperty = propertyName == null;
    StringBuilder sb = new StringBuilder();
    PropertyDescriptor pi = null;
    Type type = null;
 
    foreach (object value in source)
    {
        if (value == null)
        {
            continue;
        }
 
        if (value is string || nullProperty)
        {
            //value是string或propertyName是空的直接輸出。
            sb.Append(value);
        }
        else if (value is DataRow)
        {
            sb.Append(((DataRow)value)[propertyName]);
        }
        else
        {
            Type temp = value.GetType();
 
            if (type != temp)
            {
                type = temp;
                // 用TypeDescriptor.GetProperties(object)取屬性有實作ICustomTypeDescriptor,會取值自定屬性,如DataRowViw
                // 用TypeDescriptor.GetProperties(type)取屬性不會判斷ICustomTypeDescriptor。
                pi = TypeDescriptor.GetProperties(value)[propertyName];
 
                if (pi == null)
                {
                    throw new InvalidOperationException(string.Format("{0} Property {1} Not Exist.", type, propertyName));
                }
            }
 
            sb.Append(pi.GetValue(value));
        }
 
        sb.Append(separator);
    }
 
    return (separator == null || sb.Length == 0) ? sb.ToString() : sb.ToString(0, sb.Length - separator.Length);
}
}

 

單元測試

public class Test
{
    public string P1 { get; set; }
    public int P2 { get; set; }
 
    public override string ToString()
    {
        return this.P1;
    }
}
 
[TestMethod()]
public void JoinTest()
{
    IEnumerable source = null;
 
    //String
    source = new string[] { "A", "B", "C" };
    Assert.AreEqual(source.Join(), "A,B,C");
    Assert.AreEqual(source.Join(separator : "|"), "A|B|C");
 
    //List + class
    source = new List<Test> { new Test() { P1 = "A", P2 = 1 }, new Test() { P1 = "B", P2 = 2 }, new Test() { P1 = "C", P2 = 3 } };
    Assert.AreEqual(source.Join(), "A,B,C");
    Assert.AreEqual(source.Join("P2"), "1,2,3");
 
    //DataTable And DataView
    DataTable dt = new DataTable();
    dt.Columns.Add("Col1");
    dt.Columns.Add("Col2");
    dt.Rows.Add("A", 1);
    dt.Rows.Add("B", 2);
    dt.Rows.Add("C", 3);
 
    Assert.AreEqual(dt.Rows.Join("Col1"), "A,B,C");
    Assert.AreEqual(dt.Rows.Join("Col2"), "1,2,3");
 
    Assert.AreEqual(dt.DefaultView.Join("Col1"), "A,B,C");
    Assert.AreEqual(dt.DefaultView.Join("Col2"), "1,2,3");
 
    //IQueryable
    TestDataContext db = new TestDataContext();
    source = (from e in db.Employers
                select e).Take(3);            
 
    Assert.AreEqual(source.Join("Name"), "A,B,C");
}

 

註:原本是在2008的,Method有多載,换到2010就小小的改寫成使用預設值。