2008-12-09 54 views
5

Trong C#, tôi đang cố gắng để xây dựng một phương pháp mở rộng cho StringBuilder gọi AppendCollection() mà sẽ cho phép tôi làm điều này:StringBuilder cho phụ thêm một bộ sưu tập trong C#

var sb1 = new StringBuilder(); 
var sb2 = new StringBuilder(); 
var people = new List<Person>() { ...init people here... }; 
var orders = new List<Orders>() { ...init orders here... }; 

sb1.AppendCollection(people, p => p.ToString()); 
sb2.AppendCollection(orders, o => o.ToString()); 

string stringPeople = sb1.ToString(); 
string stringOrders = sb2.ToString(); 

stringPeople sẽ kết thúc với một cho mỗi người trong danh sách. Mỗi dòng sẽ là kết quả của p.ToString(). Tương tự như vậy đối với chuỗiOrders. Tôi không hoàn toàn chắc chắn làm thế nào để viết mã để làm cho lambdas làm việc với Generics.

+0

Bất kỳ lý do bạn không muốn sử dụng String.Join() cho việc này? – philsquared

+1

Tôi muốn có thể vượt qua trong một lambda như một trình định dạng để bạn có thể làm những việc như sb1.AppendCollection (người, => p.FirstName + "" + p.LastName); –

Trả lời

9

Sử dụng đại biểu Func<T,string>.

public static void AppendCollection<T>(this StringBuilder sb, 
             IEnumerable<T> collection, Func<T, string> method) { 
    foreach(T x in collection) 
     sb.AppendLine(method(x)); 
} 
+0

Tôi không thích điều này vì nó phá vỡ mô hình của StringBuilder. Các phương thức trên StringBuilder chỉ nên tiếp tục thêm vào bộ đệm bên trong cho đến khi ToString được gọi trên trình xây dựng. Điều này kết hợp các bước chắp thêm/chuỗi và không giống như các phương thức chắp thêm khác trên StringBuilder. – tvanfosson

+0

Chắc chắn, tôi đã cập nhật câu trả lời để đề cập đến ý kiến ​​của tôi về vấn đề này, nhưng nó được hỏi cụ thể trong câu hỏi. –

+0

Tôi đồng ý hoàn toàn. Tôi đã gõ mã ví dụ đó một chút quá nhanh. Tôi đã cập nhật câu hỏi. –

2

Phương pháp này giả sử để trả lại là gì? Tôi có thể thấy một chuỗi, nhưng tại sao, nếu bạn đang phụ thêm vào một StringBuilder?

Những gì bạn đang cố gắng làm là khá dễ dàng, nhưng bạn cần phải giải thích chính xác những gì bạn muốn.

Cập nhật:

Dưới đây là quan điểm của tôi. Sử dụng một phương pháp mở rộng cho điều này là ngu ngốc và vô nghĩa nếu bạn chỉ cần đi qua trong một StringBuilder mới và trả về một chuỗi.

Cập nhật 2:

Bây giờ tôi thấy rằng việc sử dụng, những gì bạn đang làm là xấu thực hành.

public static string Print<T>(this IEnumerable<T> col, Func<T,string> printer) 
{ 
    var sb = new StringBuilder(); 
    foreach (T t in col) 
    { 
    sb.AppendLine(printer(t)); 
    } 
    return sb.ToString(); 
} 

string[] col = { "Foo" , "Bar" }; 
string lines = col.Print(s => s); 

Cập nhật 3::

Sau khi làm rõ hơn: những gì bạn lý tưởng nên làm một cái gì đó như là

public static void AppendCollection<T>(this StringBuilder sb, 
    List<T> col, Func<T,string> printer) 
{ 
    col.ForEach(o => sb.AppendLine(printer(o))); 
} 

(mà cũng giống như bruno conde nói)

Và bây giờ bạn không thực sự cần nó nữa :)

+0

Vì vậy, tôi bị bỏ phiếu xuống, bởi vì tôi yêu cầu làm rõ? Đó là tinh thần ... – leppie

+0

Tôi nghĩ rằng vấn đề là bài viết của bạn không phải là câu trả lời, đó là một câu hỏi. Tôi không bầu bạn xuống. –

+0

Vì vậy, tôi đã nói chuyện với bản thân mình? – leppie

3

Tôi không chắc chắn bạn cần phải làm việc quá khó:

public static void AppendCollection(this StringBuilder builder, 
             ICollection collection) 
{ 
    foreach (var item in collection) 
    { 
     builder.AppendLine(Convert.ToString(item)); 
    } 
} 

Được sử dụng như

List<Person> people = ... 

StringBuilder builder = new StringBuilder(); 
builder.AppendCollection(people); 
var s = builder.ToString(); 

Tất nhiên, người cần phải ghi đè ToString() để tạo đầu ra đúng cho một đối tượng Person.

+0

Bằng cách sử dụng lambda, bạn có thể định dạng mục trong bộ sưu tập bao giờ bạn muốn. –

+0

Chắc chắn, nhưng bạn chỉ cần gọi ToString() – tvanfosson

+0

Tôi có lẽ nên đã viết một cái gì đó giống như sb1.AppendCollection (p.FirstName + "" + p.LastName) trong ví dụ. Đó là sự linh hoạt tôi thích trong chức năng này. –

3

Cái gì như:

public static void AppendCollection<TItem>(this StringBuilder builder, IEnumerable<TItem> items, Func<TItem, string> valueSelector) 
    { 
     foreach(TItem item in items) 
     { 
      builder.Append(valueSelector(item)); 
     } 
    } 

tôi sẽ thêm vào một mặc định hữu ích để tiết kiệm specifiying lambda trong 90% các trường hợp ...

public static void AppendCollection<TItem>(this StringBuilder builder, IEnumerable<TItem> items) 
    { 
     AppendCollection(builder, items, x=>x.ToString()); 
    } 
2
static class SBExtention 
{ 
    static string AppendCollection<T>(this StringBuilder sb, 
            IEnumerable<T> coll, 
            Func<T,string> action) 
    { 
     foreach(T t in coll) 
     { 
      sb.Append(action(t)); 
      sb.Append("\n"); 
     } 
     return sb.ToString(); 

    } 
} 

Tuy nhiên, tôi nghĩ rằng bạn' sẽ được tốt hơn off có nó trở về StringBuilder. Bằng cách đó bạn có thể chuỗi nó:

static StringBuilder AppendCollection<T>(this StringBuilder sb, 
            IEnumerable<T> coll, 
            Func<T,string> action) 
    { 
     // same 
     return sb; 

    } 

chuỗi peopleAndOrders = sb.AppendCollection (người, p => p.ToString()) .AppendCollection (đơn đặt hàng, o => o.ToString()). ToString();

Và tôi đồng ý với Jennifer về trường hợp mặc định:

public static StringBuilder AppendCollection<TItem>(
        this StringBuilder builder, 
        IEnumerable<TItem> items) 
    { 
     return AppendCollection(builder, items, x=>x.ToString()); 
    } 

chuỗi peopleAndOrders = sb.AppendCollection (người) .AppendCollection (đơn đặt hàng) ToString();

+0

Điều chuỗi là tốt đẹp, nhưng tôi thường thích phương pháp mở rộng của tôi về cơ bản làm việc theo cùng một cách như các phương pháp khác trên lớp. Thay đổi mô hình cơ bản về cách hoạt động của nó làm cho việc hiểu khó hơn. – tvanfosson

4
public static void AppendCollection<T>(this StringBuilder builder, IEnumerable<T> list, Func<T,string> func) 
     { 
      foreach (var item in list) 
      { 
       builder.AppendLine(func(item)); 
      } 
     } 

tôi sẽ không trả về một chuỗi, tôi sẽ chỉ gắn nó vào StringBuilder ban đầu mà được thông qua năm

+0

Vâng, tôi đồng ý.Đó là một sai lầm. Tôi đã cập nhật câu hỏi. –

3

phiên bản của tôi:.

public static string AppendCollection<T>(this StringBuilder sb, IEnumerable<T> enumerable, Func<T, string> method) 
    { 
     List<T> l = new List<T>(enumerable); 
     l.ForEach(item => sb.AppendLine(method(item))); 
     return sb.ToString(); 
    } 

nhưng bạn không nên trả lại một trong trường hợp này. Tôi muốn sau:

public static void AppendCollection<T>(this StringBuilder sb, IEnumerable<T> enumerable, Func<T, string> method) 
    { 
     List<T> l = new List<T>(enumerable); 
     l.ForEach(item => sb.AppendLine(method(item))); 
    } 

sẽ được sử dụng như:

 sb.AppendCollection(people, p => p.ToString()); 
     sb.AppendCollection(orders, o => o.ToString()); 
     Console.WriteLine(sb.ToString()); 
+0

Tôi đồng ý rằng tôi không nên trả lại chuỗi. Tôi đã cập nhật câu hỏi. –

Các vấn đề liên quan