2010-02-13 52 views
23

Có một số câu hỏi liên quan herehere, nhưng chúng không thực sự mang lại cho tôi câu trả lời thỏa đáng. Vấn đề là các enums lồng trong một lớp trong C# không thể có cùng tên như một thuộc tính của lớp. Ví dụ của tôi:Xung đột Enum và Xung đột đặt tên thuộc tính

public class Card 
{ 
    public enum Suit 
    { 
     Clubs, 
     Diamonds, 
     Spades, 
     Hearts 
    } 

    public enum Rank 
    { 
     Two, 
     Three, 
     ... 
     King, 
     Ace 
    } 

    public Suit Suit { get; private set; } 
    public Rank Rank { get; private set; } 
    ... 
} 

Có một vài tùy chọn để giải quyết vấn đề này, nhưng có vẻ như không phù hợp với tôi.

Tôi có thể di chuyển các enums ra ngoài lớp học, nhưng sau đó bạn chỉ cần nói Suit thay vì Card.Suit, điều này có vẻ sai với tôi. Suit nằm ngoài ngữ cảnh của Card là gì?

Tôi có thể di chuyển chúng ra ngoài lớp và thay đổi chúng thành một thứ như CardSuitCardRank, nhưng sau đó tôi cảm thấy như tôi đang nướng thông tin ngữ cảnh vào tên của enum, khi điều đó phải được xử lý bởi một lớp hoặc tên không gian tên.

Tôi có thể thay đổi tên của các enums thành SuitsRanks, nhưng điều này vi phạm Microsoft's naming guidelines. Và nó không cảm thấy đúng.

Tôi có thể thay đổi tên thuộc tính. Nhưng với cái gì? Nó cảm thấy trực giác với tôi muốn nói Suit = Card.Suit.Spades.

Tôi có thể di chuyển các enums vào một lớp tĩnh riêng biệt được gọi là CardInfo chỉ chứa các enums này. Nếu tôi không thể nghĩ ra điều gì khác, tôi nghĩ đây là lựa chọn tốt nhất.

Vì vậy, tôi tự hỏi những gì người khác đã làm trong các tình huống tương tự. Nó cũng sẽ được tốt đẹp để biết lý do tại sao điều này là không được phép. Có lẽ Eric Lippert hay ai đó có thể kêu gọi quyết định cấm nó? Dường như nó chỉ tạo ra sự mơ hồ trong lớp học và điều này có thể được giải quyết bằng cách buộc sử dụng this.Suit cho tên thuộc tính. (Tương tự như định hướng giữa người dân địa phương và các thành viên.) Tôi cho rằng điều này đã bị bỏ sót do điều "every feature starts with -100 points", nhưng tôi sẽ tò mò về các cuộc thảo luận xung quanh vấn đề này.

+1

Cảm ơn phản hồi, mọi người. Tôi đang đi với 'CardInfo', nhưng tôi không nghĩ có một câu trả lời kinh điển ở đây. Có rất nhiều lựa chọn phong nha, và tôi nghĩ nó đi theo phong cách. –

+0

Làm tổ 'enum' là ok nếu bạn định sử dụng chúng chỉ (chủ yếu?) Bên trong lớp. Sau đó, bạn phải đặt tên 'enum' * hơi * khác (thêm * Loại *, * Chế độ *, * Tùy chọn *, v.v ...) để tránh xung đột tên với trường/thuộc tính. Nếu có nhiều người dùng 'enum' bên ngoài lớp, thì việc lồng nhau là một ý tưởng tồi. Bạn có thể khai báo nó trong cùng một tệp cs (để có ít nhất một số loại quan hệ với lớp mà nó được sử dụng). Làm tổ là không mong muốn trong wpf quá (không nhất thiết phải 'enum', nhưng nói chung). – Sinatr

Trả lời

18

Nó cũng sẽ được tốt đẹp để biết tại sao điều này là không được phép. Có lẽ Eric Lippert hay ai đó có thể kêu gọi quyết định cấm nó?

Điểm của quy tắc là để đảm bảo rằng không có sự mơ hồ trong lớp khi tra cứu tên. Một số vùng mã được chỉ định là xác định 'không gian khai báo'. Nguyên tắc cơ bản của không gian khai là không có hai điều tuyên bố trong không gian khai cùng có cùng tên (trừ phương pháp, trong đó phải khác nhau bởi chữ ký, không tên.)

Làm ngoại lệ cho quy tắc này chỉ làm cho mọi thứ trở nên khó hiểu hơn, không ít gây nhầm lẫn. Tôi đồng ý rằng nó là vexing rằng bạn không thể có một tài sản và enum của cùng một tên tuyên bố trong cùng một không gian khai báo, nhưng một khi bạn bắt đầu thực hiện trường hợp ngoại lệ sau đó nó chỉ được một mess. Nó thường là một tài sản tốt đẹp mà một tên duy nhất xác định một nhóm phương pháp, loại tham số, tài sản, và như vậy.

Lưu ý rằng quy tắc này áp dụng cho mọi thứ được khai báo trong không gian khai báo, không phải mọi thứ được sử dụng trong không gian khai báo. Hoàn toàn hợp pháp để nói "Suit Suit công cộng {get; set;}" với điều kiện là loại Suit không được khai báo trong cùng một không gian khai báo như thuộc tính. Khi ai đó nói "Suit.X", tìm hiểu xem X có thuộc loại (tức là, X là một thành viên tĩnh) hay thuộc tính (tức là X là một thành viên thể hiện) là một chút khó khăn. Xem bài viết của tôi về cách chúng tôi làm điều đó để biết chi tiết:

http://blogs.msdn.com/ericlippert/archive/2009/07/06/color-color.aspx

+0

Điều đó có ý nghĩa với tôi. Cảm ơn bạn về thông tin! –

+0

Có bất kỳ loại quy ước đặt tên chuẩn nào để xử lý vấn đề này không? Trong trường hợp cụ thể của tôi, tôi đang cố gắng tạo một cấu trúc lớp lồng nhau để giữ các giá trị của một tệp cài đặt phân cấp (json). Xu hướng tự nhiên của tôi là đặt tên cho các thuộc tính giống như lớp lồng nhau (ví dụ, nếu tôi có một lớp lồng nhau 'Settings.Color', tôi muốn có' màu công cộng {get; set;} '), nhưng tất nhiên điều này sẽ không biên dịch. Tùy chọn của tôi dường như là đổi tên lớp hoặc thuộc tính, ví dụ: 'ColorInfo', nhưng điều này có thể dẫn đến tên xấu cho các mục sâu trong cấu trúc phân cấp. – devuxer

+0

@devuxer: Tôi không biết cách nào tốt để giải quyết vấn đề đó, nhưng thông thường nó không phải là một mối quan tâm bởi vì nó được coi là một mùi hôi để tạo ra một loại lồng nhau công cộng. Nếu loại lồng nhau không được công khai thì bạn sẽ không bao giờ có thuộc tính công khai hiển thị loại như vậy. Tôi sẽ tránh các loại lồng nhau; Tôi chỉ sử dụng chúng khi loại lồng nhau là một chi tiết thực hiện riêng tư của loại bên ngoài. –

3

Tôi thích đặt tên cho enums bằng danh từ, sau đó là Tùy chọn. Trong trường hợp của bạn:

SuitOptions 
RankOptions 

Sau khi tất cả, enum chỉ là một tập hợp các tùy chọn có thể, phải không?

Bạn sẽ có sau đó:

myCard.Suit = Card.SuitOptions.Clubs; 

Mà theo ý kiến ​​của tôi có ý nghĩa và bạn vẫn có thể biết khi xem văn bản cho dù là sau đó enum hoặc bất động sản.

+1

Kể từ khi enum là một tập hợp các tùy chọn theo định nghĩa, có vẻ như dư thừa để nướng mà vào tên. Nó có vẻ tương đương với việc thêm một hậu tố -Enum, mà các hướng dẫn phong cách nói không làm. –

+0

Tôi đồng ý rằng thêm hậu tố -Enum là thừa nhưng tôi vẫn tin rằng -Options là một lựa chọn tốt bởi vì: nó mô tả loại đó là gì trong khi chỉ "Suits" sẽ khiến tôi nghĩ đến một bộ sưu tập phù hợp và đơn giản "Suit" không làm việc trong ngữ cảnh này. –

+1

Có bất kỳ enums nào mà bạn cho rằng -Options là hậu tố không thích hợp không? Tôi không thể nghĩ về bất cứ nơi nào nó sẽ không * phù hợp, mà tôi nghĩ là vấn đề - nó quá chung chung. Nó giống như -Quản lý hoặc -Helper trên một lớp học. –

1

Tôi sẽ di chuyển các liệt kê bên ngoài định nghĩa lớp và sử dụng không gian tên để chỉ ra rằng chúng liên quan đến thẻ. Tôi thường không thích enums lồng trong lớp học. Bạn đang đúng về đa số, mặc dù: số ít cho enums thường xuyên, số nhiều cho lá cờ enums.

+0

Đó là một tùy chọn khác, nhưng bạn nhanh chóng chạy vào các vấn đề tương tự. Không gian tên nên được gọi là gì? 'Thẻ' đã hết, kể từ đó nó sẽ xung đột với tên lớp. Bạn có thể lồng nó xuống một cấp độ khác trong không gian tên 'Enums', tôi đoán vậy. Một cái gì đó giống như 'Core.Enums.Card', nơi chính lớp đó là' Core.Card'. Đó không phải là một lựa chọn tồi. –

1

Enums của bạn về cơ bản là các kiểu dữ liệu mà bạn đã xác định. Bạn sẽ không sử dụng 'int' hoặc 'string' làm tên thành viên, vì vậy tôi nghĩ rằng đó là một ý tưởng không kém khi sử dụng tên enum và tên thành viên trong trường hợp của bạn.

+0

Vì vậy, bạn sẽ đặt tên cho chúng trong trường hợp * cụ thể * này? 'int' và' string' là những thứ rất chung chung, nhưng 'Suit' và' Rank' chỉ có ý nghĩa trong ngữ cảnh của 'Thẻ'. –

+0

Tôi thực sự ghét nó khi một vị trí triết học hoàn hảo bị vấp ngã bởi thực tế thực tế :) Trong kế hoạch đặt tên của riêng tôi, tôi luôn sử dụng camelCase cho tên thuộc tính của mình. . Nếu bạn không thể làm điều đó, thì tôi thích ý tưởng lớp CardInfo của bạn. Và CardSuit (như bạn đề nghị) hoặc SuitOptions (từ Victor) cũng không tệ. Thỉnh thoảng, tôi đoán, việc đặt tên cho thế giới thực, hợp lý của các đối tượng của chúng ta không khớp với những gì trình biên dịch cho phép chúng ta làm. – Ray

+0

Đúng. Có một vài lựa chọn phong nha trong câu trả lời ở đây, nhưng không ai cảm thấy * lý tưởng *. Tôi đang nghiêng về phía thứ 'CardInfo' của mình, nhưng tôi sẽ, phải không? Tôi đã đề nghị nó, sau khi tất cả. Tôi nghĩ rằng đây phần lớn là một sự lựa chọn phong cách. –

3

Tôi đồng ý di chuyển định nghĩa enum sang một địa điểm riêng biệt.Hiện nay, sự đếm chỉ hiển thị thông qua thẻ, vì vậy nếu bạn muốn kiểm tra một ace, bạn sẽ phải làm

if (card.CardSuit == Card.Suit.Ace) { } //need different name for Suit field 

đâu nếu bạn di chuyển nó đến một định nghĩa riêng biệt, bạn có thể làm điều này nếu bạn đã thực hiện nó toàn cầu:

if (card.Suit == Suit.Ace) { } //no naming clashes, easier to read 
+1

Nested loại/enums nên tránh nếu chúng sẽ được sử dụng thường xuyên. Ví dụ, rất khó để khám phá thông qua IDE/Intellisense bởi vì ngay cả khi bạn gõ "Suit" bạn sẽ không nhận được nhắc nhở để tự động thêm 'using', vì bạn phải truy cập enum như' Card.Suit' như trong Hình ảnh của Crazy. Chỉ lồng một loại nếu nó chỉ được sử dụng trong nội bộ trong lớp, cần thiết bên ngoài rất hiếm khi, hoặc chỉ được sử dụng trong các kịch bản nâng cao như kế thừa lớp. – AaronLS

1

It't thú vị để thấy rằng trong khi Microsoft Naming Guidelines nói rằng bạn nên sử dụng một tên đặc biệt đối với hầu hết enums và tên số nhiều cho các lĩnh vực bit, the code sample for the enum keywordlàm sử dụng tên số nhiều!

enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };