2013-01-22 31 views
6

Tôi tiếp tục sử dụng chức năng bên dưới trong các lớp học của mình và muốn viết nó dưới dạng generics.Sử dụng cơ bản Generics

public static IEnumerable<MyObject> Get(string csvFile) 
{ 
    return csvFile 
     .ReadAsStream() 
     .SplitCrLf() 
     .Where(row => !string.IsNullOrWhiteSpace(row)) 
     .Select(row => new MyObject(row.Split(','))); 
} 

Tôi xước mã dưới đây nhưng đã không làm việc

public static IEnumerable<T> Get<T>(string csvFile) 
{ 
    return csvFile 
     .ReadAsStream() 
     .SplitCrLf() 
     .Where(row => !string.IsNullOrWhiteSpace(row)) 
     .Select(row => new typeof(T)(row.Split(','))); 
} 

Xin cho biết. Cảm ơn bạn!

+3

Không hoạt động, theo cách nào? – JLRishe

+1

Có lẽ không biên dịch, vì 'new typeof (T)' là cú pháp không hợp lệ. – cdhowie

+0

Bạn có thể tạo một 'IEnumerable ' từ tệp csv. Để chuyển nó thành một 'IEnumerable ', bạn sẽ cần định nghĩa một hàm chuyển đổi 'Func ' và áp dụng nó. – ja72

Trả lời

11

Bạn không thể sử dụng new để tạo các trường hợp sử dụng các loại chung theo cách này . Xem xét cung cấp một đại biểu nhà máy với chức năng:

public static IEnumerable<T> Get<T>(string csvFile, Func<string[], T> factory) 
{ 
    return csvFile 
     .ReadAsStream() 
     .SplitCrLf() 
     .Where(row => !string.IsNullOrWhiteSpace(row)) 
     .Select(row => factory(row.Split(','))); 
} 

Sau đó, bạn sẽ gọi nó là như vậy:

var myObjects = Get("file.csv", row => new MyObject(row)); 

Ngoài ra, bạn có thể trở lại một IEnumerable<string[]> và để cho người gọi quyết định làm gì với nó:

public static IEnumerable<string[]> Get(string csvFile) 
{ 
    return csvFile 
     .ReadAsStream() 
     .SplitCrLf() 
     .Where(row => !string.IsNullOrWhiteSpace(row)) 
     .Select(row => row.Split(',')); 
} 

Sau đó người gọi có thể làm:

01.
var myObjects = Get("file.csv").Select(row => new MyObject(row)); 

Bạn có thể cung cấp các where T : new() hạn chế và sau đó bạn có thể tạo ra các trường hợp mới sử dụng một kiểu generic, nhưng chỉ khi nó cung cấp một constructor không có đối số; bạn không thể cung cấp các đối số khi xây dựng các kiểu generic và trường hợp sử dụng của bạn dường như yêu cầu nó. Một đại biểu nhà máy là lựa chọn tốt nhất của bạn ở đây.

Để tham khảo, đây là cách xây dựng sử dụng các loại generic sẽ tìm trong các trường hợp không tham số:

public static T Create<T>() where T : new() 
{ 
    return new T(); 
} 

Thậm chí tốt hơn sẽ là một IEnumerable<IEnumerable<string>> giả định rằng constructor MyObject của bạn chấp nhận IEnumerable<string> là tốt.

+0

mặc dù, có [Activator.CreateInstance] (http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx). Đề xuất tốt, mặc dù +1 – Default

+2

@Default Thực tế là có. Trong thực tế, 'new T()' được biên dịch thành 'Activator.CreateInstance ()'. Tuy nhiên, người ta nên lưu ý rằng kỹ thuật này (sử dụng CreateInstance để truyền các đối số cho một hàm khởi tạo) sẽ sử dụng sự phản chiếu mỗi lần, phát sinh một hình phạt hiệu năng có khả năng nghiêm trọng. Sử dụng một đại biểu nhà máy không chỉ mang lại sự linh hoạt hơn (có thể bạn muốn làm nhiều hơn là chỉ xây dựng một đối tượng) trong khi cũng sử dụng mã được biên dịch và tránh chi phí phản chiếu. – cdhowie

+0

bổ sung tuyệt vời! Tôi không biết điều đó. – Default

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