6

Có thể sử dụng thuộc tính trong C# bằng bộ khởi tạo bộ sưu tập không?Tôi có thể sử dụng bộ khởi tạo bộ sưu tập cho Thuộc tính không?

Ví dụ, tôi muốn làm một cái gì đó như sau:

[DictionaryAttribute(){{"Key", "Value"}, {"Key", "Value"}}] 
public class Foo { ... } 

Tôi biết các thuộc tính có thể có tên là tham số, và từ đó có vẻ khá giống với đối tượng initializers, tôi đã tự hỏi nếu initializers bộ sưu tập là cũng có sẵn.

+0

Scott, Xin lỗi - câu trả lời của tôi không thành công. Tôi không kiếm được phiếu bầu. Hãy bình chọn xuống cos chơi công bằng của nó. – vladimir77

+0

@ vladimir77 - Bạn không nên xóa câu trả lời của mình! Đôi khi câu trả lời sai vẫn hữu ích ... chỉ cần cập nhật câu trả lời của bạn lần sau, để mọi người có thể hiểu tại sao nó sai. –

+0

Ok. :) Ive khôi phục lại nó. – vladimir77

Trả lời

6

Cập nhật : Tôi xin lỗi tôi nhầm - vượt qua hàng loạt các kiểu tùy chỉnh là không thể :(

Các loại tham số vị trí và đặt tên cho một lớp thuộc tính được giới hạn cho các loại tham số thuộc tính, đó là:

  1. Một trong các loại sau: bool, byte, char, double, float, int, dài, ngắn, chuỗi.
  2. Đối tượng loại.
  3. Loại System.Type.
  4. Loại Enum, miễn là nó có khả năng truy nhập công cộng và các loại trong đó lồng nhau (nếu có) cũng có thể truy cập công cộng (Mục 17.2).
  5. Mảng đơn chiều của phía trên loại. source

Nguồn: stackoverflow.

Bạn có thể khai báo thông qua một loạt các kiểu tùy chỉnh:

class TestType 
{ 
    public int Id { get; set; } 
    public string Value { get; set; } 

    public TestType(int id, string value) 
    { 
    Id = id; 
    Value = value; 
    } 
} 

class TestAttribute : Attribute 
{ 
    public TestAttribute(params TestType[] array) 
    { 
    // 
    } 
} 

nhưng biên soạn các lỗi xảy ra trên tờ khai thuộc tính:

[Test(new[]{new TestType(1, "1"), new TestType(2, "2"), })] 
public void Test() 
{ 

} 
+0

Vì bạn có 'params' trong đó, bạn có thể bỏ qua' new [] {...} 'cho một cú pháp đẹp hơn nhiều. Tuy nhiên, bạn có chắc là biên dịch này không? Tôi nghĩ rằng đối số thuộc tính có giới hạn - biểu thức liên tục, biểu thức typeof hoặc biểu thức tạo mảng - như đã được đề cập bởi @Jason Down. –

+1

@Scott: đó là _is_ một biểu thức tạo mảng. :) (Nhân tiện, tôi sẽ xóa câu trả lời của tôi; như Jason đã chỉ ra là không tốt.) –

+0

Im xin lỗi Im không thành công: ( – vladimir77

3

Câu trả lời ngắn gọn là không.

Câu trả lời dài hơn: Để một lớp hỗ trợ trình khởi tạo bộ sưu tập, nó cần triển khai IEnumerable và cần phải có phương thức bổ sung. Vì vậy, ví dụ:

public class MyClass<T,U> : IEnumerable<T> 
{ 
    public void Add(T t, U u) 
    { 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Sau đó tôi có thể làm điều này:

var mc = new MyClass<int, string> {{1, ""}, {2, ""}}; 

Vì vậy, sử dụng này, chúng ta hãy cố gắng để làm cho nó làm việc cho một thuộc tính. (Mặt lưu ý, vì các thuộc tính không hỗ trợ Generics, tôi chỉ hardcoding nó sử dụng dây để thử nghiệm):

public class CollectionInitAttribute : Attribute, IEnumerable<string> 
{ 
    public void Add(string s1, string s2) 
    { 

    } 

    public IEnumerator<string> GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

Và bây giờ để kiểm tra nó:

[CollectionInit{{"1","1"}}] 
public class MyClass 
{ 

} 

và điều đó không biên dịch :(Tôi không chắc chắn nơi giới hạn là chính xác, tôi đoán thuộc tính không phải là mới lên cùng một cách một đối tượng thường xuyên và do đó điều này không được hỗ trợ. Tôi muốn tò mò nếu điều này về mặt lý thuyết có thể được hỗ trợ bởi một phiên bản tương lai của ngôn ngữ ....

+0

Cảm ơn bạn đã trả lời ngắn và câu trả lời dài của bạn! Đó là chính xác những gì tôi đã thử quá, nhưng khi nó không biên dịch, tôi đã không chắc chắn nếu nó là một cú pháp bị lỗi hoặc một tính năng không được hỗ trợ. Tôi cũng không biết rằng Generics không được phép. –

+0

FYI Tôi thích câu trả lời của bạn rất nhiều, nhưng tôi quyết định chấp nhận câu trả lời của @ vladimir77 chỉ bởi vì nó có một câu trả lời dứt khoát được trích dẫn từ MSDN, và nó có vẻ là câu trả lời tốt nhất cho câu hỏi. –

+0

@scott: không có vấn đề gì lớn. Tôi chỉ muốn chỉ ra rằng đây không phải là một vấn đề của các tham số được đặt tên, vì đó không phải là những gì bạn đang cố gắng làm. Bạn đang cố gắng sử dụng cú pháp intializer bộ sưu tập, đó là một điều riêng biệt hoàn toàn ... – BFree

5

Mục 17.1.3 của đặc tả C# 4.0 đặc biệt không cho phép các mảng đa chiều bên trong các tham số thuộc tính, vì vậy trong khi Foo (chuỗi [,] thanh) có thể cho phép bạn gọi Foo (new [,] {{"a", "b"}, {"key2", "val2"} }), thật không may, không có sẵn cho các thuộc tính.

Vì vậy, với ý nghĩ đó, một vài khả năng để xấp xỉ những gì bạn muốn là:

  1. Sử dụng một mảng đơn chiều, với xen kẽ cặp khóa và giá trị. Nhược điểm rõ ràng của phương pháp này là nó không thực thi chính xác tên và giá trị.

  2. phép tham số của bạn xuất hiện nhiều lần bằng cách gắn thẻ định nghĩa thuộc tính của bạn với các thuộc tính sau:

    [AttributeUsage(AllowMultiple=true)] 
    

    Bằng cách này, bây giờ bạn có thể định nghĩa:

    [KeyVal("key1","val1"), KeyVal("key2","val2")] 
    public class Foo { ... } 
    

    Đây là một chút wordier so với những gì tôi chắc chắn bạn đang hy vọng, nhưng nó làm cho một sự phân định rõ ràng giữa tên và giá trị.

  3. Tìm gói JSON và cung cấp bộ khởi tạo cho thuộc tính của bạn. Hiệu suất đạt được là không quan trọng vì điều này được thực hiện trong quá trình khởi tạo mã. Sử dụng Newtonsoft.Json, ví dụ, bạn có thể làm cho một thuộc tính như vậy:

    public class JsonAttribute : Attribute 
        { 
         Dictionary<string, string> _nameValues = 
          new Dictionary<string, string>(); 
         public JsonAttribute(string jsoninit) 
         { 
         var dictionary = new Dictionary<string, string>(); 
         dynamic obj = JsonConvert.DeserializeObject(jsoninit); 
         foreach(var item in obj) 
          _nameValues[item.Name] = item.Value.Value; 
         } 
        } 
    

    Mà sau đó sẽ cho phép bạn nhanh chóng một thuộc tính như vậy:

    [Json(@"{""key1"":""val1"", ""key2"":""val2""}")] 
    public class Foo { ... } 
    

    Tôi biết đó là một chút quote-hạnh phúc , nhiều hơn nữa có liên quan, nhưng có bạn đang có. Bất kể, trong thế giới năng động điên rồ này, việc biết cách khởi tạo các đối tượng bằng JSON không phải là một kỹ năng tồi để có trong túi sau của bạn.

+0

Cảm ơn đề xuất của bạn # 1 có vẻ như một giải pháp khá tốt # 2 là một giải pháp tuyệt vời cho một số tình huống, nhưng không hoạt động cho tất cả các tình huống. Và # 3 ... nói về quá mức cần thiết, nhưng cảm ơn cho suy nghĩ bên ngoài hộp! –

+0

Thú vị đủ, giải pháp # 3 có nhiều khả năng nhất để kiểm tra thời gian, vì bất kỳ thuộc tính bổ sung nào mà bạn muốn sử dụng kỹ thuật này có thể được lấy trực tiếp từ JsonAttribute.Nhưng nếu một giải pháp không biên dịch là những gì bạn đang có, tôi chắc chắn một trong những câu trả lời khác sẽ được nhiều hơn theo ý thích của bạn. ;-) –

+0

Đó là sự thật, giải pháp của bạn là những người duy nhất biên dịch :) –

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