2015-01-23 16 views
5

Trong quá trình phát triển một trong các dự án của tôi, tôi gặp phải một vấn đề liên quan đến các loại chung chung.Khởi tạo một loạt các bộ sưu tập chung với mỗi đối số chung khác nhau

Dự án yêu cầu tôi viết một lớp hoạt động như một nguồn của các đối tượng danh sách. Giả sử tôi có lớp sau:

public class TablesProvider 
{ 
    private readonly List[] _tables; 

    public TablesProvider() 
    { 
     // initialize the tables var here.... 
    } 

    public List<TItem> GetTable<TItem>() 
    { 
     return (List<TItem>)_tables.Single(x => x is List<TItem>); 
    } 
} 

Lớp này rõ ràng là không làm việc, bởi vì loại List là một kiểu generic và do đó các đối số chung nên được chỉ định.

Vì vậy, tôi đã tạo một loại trừu tượng có tên là MyList, có thể bắt nguồn từ loại cụ thể hơn MyList<TItem> để thoát khỏi yêu cầu này và chỉnh sửa TablesProvider một chút.

public class TablesProvider 
{ 
    private readonly MyList[] _tables; 

    public TablesProvider() 
    { 
     // initialize the tables var here.... 
    } 

    public MyList<TItem> GetTable<TItem>() 
    { 
     return (MyList<TItem>)_tables.Single(x => x is MyList<TItem>); 
    } 
} 

public abstract class MyList 
{ 
    // ... 
} 

public class MyList<TItem> : MyList, IList<TItem> 
{ 
    private readonly List<TItem> _elements = new List<TItem>(); 

    public TItem this[int index] 
    { 
     get { return _elements[index]; } 
     set { _elements[index] = value; } 
    } 

    // ... 
} 

Điều này hoạt động khá tốt. Chỉ còn lại một vấn đề. Giả sử tôi có 45 bộ sưu tập khác nhau, mỗi bộ được định nghĩa với một đối số chung khác nhau. Điều gì sẽ là cách tốt nhất để khởi tạo tất cả các bộ sưu tập đó? Tôi không thể sử dụng một vòng lặp for ở đây, vì các thông số chung chung được quy định tại thời gian biên dịch và không phải ở thời gian chạy, và do đó một công trình như thế này sẽ không thể thực hiện:

for (int i = 0; i < 45; i++) 
     _tables[i] = new MyList<GenericParameters[i]>(); 

mục tiêu cuối cùng của tôi là để có sự sang trọng để chỉ cần làm một cái gì đó như thế này ...

var table = _tablesProvider.GetTable<SomeClass>(); 
var element = table[3]; 
var propertyValue = element.SomeProperty; 

... mà không cần phải biến biến element để truy cập các thành viên loại cụ thể của nó.

Có thể đáng nói rằng số lượng đối tượng danh sách khác nhau được cố định là 45. Điều này sẽ không thay đổi. Về lý thuyết, tôi có thể khởi tạo dòng mảng theo dòng hoặc có 45 thuộc tính hoặc biến thay thế. Tuy nhiên, cả hai tùy chọn này đều là một giải pháp khá rẻ đối với tôi, nhưng tôi sẽ chấp nhận một trong số chúng nếu không có cách nào khác.

Bạn có ý tưởng nào không? Tôi làm điều này hoàn toàn sai? Tôi có nên xem xét một cấu trúc khác không?

Xin cảm ơn trước.

Trả lời

1

thực hiện các công trình này

public class TablesProvider 
{ 
    private readonly List<object> _tables; 

    public TablesProvider() 
    { 
     _tables = new List<object>(); 
    } 

    public IList<TItem> GetTable<TItem>() 
    { 
     var lst = (List<TItem>)_tables.SingleOrDefault(x => x is List<TItem>); 
     if (lst == null) 
     { 
      lst = new List<TItem>(); 
      _tables.Add(lst); 
     } 
     return lst; 
    } 
} 

nó tạo ra Danh sách TItem khi cần thiết; lần sau nó trả về cùng một danh sách cho TItem. đó là lười biếng khởi

vì vậy bạn có thể làm gọi

var table = _tablesProvider.GetTable<SomeClass>(); 

mà không cần bất kỳ mã như thế này:

for (int i = 0; i < 45; i++) 
    _tables[i] = new MyList<GenericParameters[i]>(); 

nó không phải là ThreadSafe

1

Vâng, chúng ta có thể làm những gì bạn đang mô tả nếu bạn sử dụng sự phản chiếu.

Giả sử rằng giả thuyết GenericParameters mảng của bạn là một mảng của Type s (kể từ khi bạn không thể có một loạt các loại định danh), bạn có thể xác định chức năng helper này:

private MyList MakeList(Type t) 
{ 
    return (MyList)Activator.CreateInstance(typeof(MyList<>).MakeGenericType(t)); 
} 

Và đó sẽ cho phép bạn làm như sau:

public TablesProvider() 
{ 
    var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) }; 

    _tables = new MyList[GenericParameters.Length]; 

    for (int i = 0; i < GenericParameters.Length; i++) 
    { 
     _tables[i] = MakeList(GenericParameters[i]); 
    } 
} 

bạn thậm chí có thể sử dụng LINQ nếu bạn muốn:

public TablesProvider() 
{ 
    var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) }; 

    _tables = GenericParameters.Select(MakeList).ToArray(); 
} 


câu trả lời trước:

Vâng, thực tế là bạn sẽ có một danh sách 45 loại khác nhau đâu đó, trong đó khá nhiều có nghĩa là bạn sẽ có 45 dòng khác nhau của tương tự mã. Vì vậy, người ta có thể nói mục đích là làm cho những dòng đó ngắn gọn nhất có thể.

Một cách để làm như vậy sẽ có thêm một chức năng helper:

private void AddTable<T>() 
{ 
    _tables.Add(new MyTable<T>()); 
} 

(điều này giả định thay đổi _tables đến một List<MyTable>)

Sau đó, bạn chỉ có thể làm:

AddTable<Type1>(); 
AddTable<Type2>(); 
AddTable<Type3>(); 
AddTable<Type4>(); 
+0

Các toàn bộ vấn đề là tránh viết 45 dòng mã. Tôi không nghĩ đó là điều anh ta đang tìm kiếm. – Tweety

+0

@Tweety Có lẽ, nhưng làm thế nào ông sẽ điền vào mảng 'GenericParameters []' giả định của mình ở nơi đầu tiên mà không có 45 dòng _something_ (có thể là mã, tệp cấu hình, v.v.)? Thiết kế đã nói của anh ta liên quan đến việc có 45 dòng thứ gì đó ở đâu đó. Nó chỉ là vấn đề của chúng ở đâu và chúng trông như thế nào. – JLRishe

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