Không gian tên và lớp có cùng tên?


95

Tôi đang tổ chức một dự án thư viện và tôi có một lớp quản lý trung tâm được đặt tên Scenegraphvà một loạt các lớp khác nằm trong không gian tên Scenegraph.

Điều tôi thực sự muốn là để cho scenegraph MyLib.Scenegraphvà các lớp khác cũng vậy MyLib.Scenegraph.*, nhưng có vẻ như cách duy nhất để làm điều đó là đặt tất cả các lớp khác bên trong các lớp Scenegraphtrong tệp Scenegraph.cs và điều đó quá khó sử dụng .

Thay vào đó, tôi đã sắp xếp nó thành Mylib.Scenegraph.ScenegraphMyLib.Scenegraph.*, loại hoạt động nào nhưng tôi thấy Visual Studio bị nhầm lẫn trong một số điều kiện về việc liệu tôi đang tham chiếu đến lớp hay không gian tên.

Có cách nào tốt để tổ chức gói này sao cho thuận tiện cho người dùng mà không cần ghép tất cả mã của tôi lại với nhau trong một mớ hỗn độn không thể xác định được không?

Câu trả lời:


111

Tôi không khuyên bạn nên đặt tên một lớp giống như không gian tên của nó, hãy xem điều này .

Nguyên tắc Thiết kế Khung nói trong phần 3.4 “không sử dụng cùng một tên cho một vùng tên và một kiểu trong vùng tên đó”. Đó là:

namespace MyContainers.List 
{ 
    public class List {  } 
}

Tại sao lại có tật xấu này? Ồ, hãy để tôi đếm các cách.

Bạn có thể rơi vào tình huống mà bạn nghĩ rằng bạn đang đề cập đến một thứ nhưng thực tế lại đang đề cập đến một thứ khác. Giả sử bạn gặp phải tình huống không may này: bạn đang viết Blah.DLL và nhập Foo.DLL và Bar.DLL, thật không may, cả hai đều có một loại được gọi là Foo:

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah  
{   
using Foo;   
using Bar;   
class C { Foo foo; } 
}

Trình biên dịch báo lỗi. “Foo” không rõ ràng giữa Foo.Foo và Bar.Foo. Bummer. Tôi đoán tôi sẽ khắc phục điều đó bằng cách xác định đầy đủ tên:

   class C { Foo.Foo foo; } 

Điều này hiện đưa ra lỗi không rõ ràng “ Foo trong Foo.Foo không rõ ràng giữa Foo.Foo và Bar.Foo ”. Chúng tôi vẫn không biết Foo đầu tiên đề cập đến điều gì, và cho đến khi chúng tôi có thể tìm ra điều đó, chúng tôi thậm chí không buồn cố gắng tìm ra cái thứ hai đề cập đến điều gì.


6
Đó là một điểm thú vị. Tôi vẫn đang say mê nó. Cảm ơn. Tôi phải thành thật lập luận bắt đầu bằng "Hướng dẫn phong cách nói" không gây ấn tượng với tôi. Tôi đã thấy rất nhiều điều tào lao vô lý trong các hướng dẫn phong cách. Nhưng bạn đưa ra một lập luận thực tế tốt ở trên. Đáng để suy nghĩ về, dù sao.
user430788 15/09/13

5
Câu trả lời là "không nên làm gì". Trong khi một số người dùng ngăn xếp tìm kiếm "phải làm gì". Có ai giới thiệu câu trả lời Ant_222 không?
fantastory

3
Nếu bạn thực sự gặp khó khăn, bạn vẫn có thể tạo bí danh kiểu bên ngoài không gian tên của mình. Bí danh bên ngoài chỉ cần thiết khi bạn có hai định danh hoàn toàn giống hệt nhau (không gian tên + tên lớp).
Geoffrey

4
Tất cả những điều trên chỉ là riêng biệt và ý kiến. Các thực tế là bạn không nên làm điều đó bởi vì các biên dịch C # sẽ hiểu lầm nó , dù đã được nói khá rõ ràng những gì đang xảy ra. Ví dụ, using Foo.Bar;sau đó Bar blà đề cập khá rõ ràng Bar, một lớp (hoặc enum) bên trong không gian tên Foo.Bar. Lý do thực sự để không làm điều đó hoàn toàn là trình biên dịch C # không hiểu chính xác nó, điều này thật đáng ngạc nhiên và đáng tiếc. Bất cứ điều gì khác là lời khuyên phong cách len.
TJ Crowder

2
Tôi không hiểu. Tại sao Foo.Foo lại mơ hồ? Bạn trực tiếp nói với trình biên dịch rằng bạn muốn sử dụng lớp Foo từ không gian tên Foo trong trường hợp cụ thể này. Không?
GuardianX

14

Đặt cùng một tên cho không gian tên và lớp có thể gây nhầm lẫn cho trình biên dịch như những người khác đã nói.

Làm thế nào để đặt tên cho nó sau đó?

Nếu không gian tên có nhiều lớp thì hãy tìm một tên xác định tất cả các lớp đó.

Nếu không gian tên chỉ có một lớp (và do đó có khả năng đặt tên cho nó giống nhau) hãy đặt tên cho không gian tên ClassName NS . Đây là cách Microsoft đặt tên cho không gian tên của họ ít nhất.


4
Bạn có ví dụ về không gian tên như vậy từ Microsoft không?
sunefred

Tôi phải tìm kiếm nó và quay lại với bạn.
GoTo

@sunefred Tôi đã tìm kiếm nó, nhưng tôi không thể tìm thấy nó. Nhưng tôi chắc chắn nhớ đã xem nó trong tài liệu. Tôi đoán rằng không có nhiều trường hợp khi bạn muốn có một lớp duy nhất trong một không gian tên.
GoTo

9

Tôi khuyên bạn nên làm theo lời khuyên mà tôi đã microsoft.public.dotnet.languages.csharpsử dụng MyLib.ScenegraphUtil.ScenegraphMyLib.ScenegraphUtil.*.


7

CA1724: Type Names Should Not Match Namespaces ...

Về cơ bản, nếu bạn tuân theo Phân tích mã để viết mã phù hợp, quy tắc này nói rằng đừng làm những gì bạn đang cố gắng làm. Phân tích mã rất hữu ích trong việc giúp bạn tìm ra các vấn đề tiềm ẩn .


4

Chỉ cần thêm 2 xu của tôi:

Tôi đã có lớp học sau:

namespace Foo {
    public struct Bar {
    }
    public class Foo {
        //no method or member named "Bar"
    }
}

Khách hàng đã được viết như thế này:

using Foo;

public class Blah {
    public void GetFoo( out Foo.Bar[] barArray ) {
    }
}

Tha thứ cho lỗi GetFoo không trả về đầu ra thay vì sử dụng tham số out, trình biên dịch không thể giải quyết kiểu dữ liệu Foo.Bar []. Nó trả về lỗi: không thể tìm thấy loại hoặc không gian tên Foo.Bar.

Có vẻ như khi nó cố gắng biên dịch nó đã giải quyết Foo dưới dạng lớp và không tìm thấy Thanh lớp được nhúng trong Foo lớp. Nó cũng không thể tìm thấy một không gian tên có tên là Foo.Bar. Nó không thành công khi tìm kiếm một thanh lớp trong không gian tên Foo. Các dấu chấm trong không gian tên KHÔNG phải là cú pháp. Toàn bộ chuỗi là một mã thông báo, không phải các từ được phân tách bằng dấu chấm.

Hành vi này đã được thể hiện bởi VS 2015 chạy .Net 4.6


4

Mặc dù tôi đồng ý với các câu trả lời khác ở chỗ bạn không nên đặt tên lớp giống với không gian tên của bạn , đôi khi bạn không thể tuân thủ các yêu cầu đó.

Ví dụ trong trường hợp của tôi, tôi không phải là người đưa ra quyết định như vậy, do đó tôi cần phải tìm cách để nó hoạt động.

Vì vậy, đối với những người không thể thay đổi tên không gian tên cũng như tên lớp, đây là một cách mà bạn có thể làm cho mã của mình hoạt động.

// Foo.DLL: 
namespace Foo { public class Foo { } }

// Bar.DLL: 
namespace Bar { public class Foo { } }

// Blah.DLL: 
namespace Blah
{
    using FooNSAlias = Foo;//alias
    using BarNSAlias = Bar;//alias
    class C { FooNSAlias.Foo foo; }//use alias to fully qualify class name
}

Về cơ bản, tôi đã tạo "bí danh" không gian tên và điều đó cho phép tôi đủ điều kiện cho lớp và "sự nhầm lẫn" của Visual Studio đã biến mất.

LƯU Ý: Bạn nên tránh xung đột đặt tên này nếu nó nằm trong tầm kiểm soát của bạn. Bạn chỉ nên sử dụng kỹ thuật đã đề cập khi bạn không kiểm soát được các lớp và không gian tên được đề cập.


2
Tôi đã bình chọn nó vì nó là một giải pháp thú vị cho một thế giới không hoàn hảo.
user430788

2

Bài cũ, nhưng ở đây tôi chuyển sang một ý tưởng khác có thể giúp ích cho ai đó:

"... nhưng có vẻ như cách duy nhất để làm điều đó là đặt tất cả các lớp khác bên trong các lớp Scenegraph trong tệp Scenegraph.cs và điều đó quá khó sử dụng."

Đây thực sự là cách triển khai tốt hơn cho nhiều tình huống. Nhưng, tôi đồng ý rằng có tất cả mã đó trên cùng một tệp .cs là điều khó chịu (ít nhất là).

Bạn có thể giải quyết nó bằng cách đặt lớp cơ sở thành "lớp một phần" và sau đó, tiếp tục tạo các lớp bên trong trên tệp của chính chúng (chỉ cần nhớ rằng chúng sẽ phải khai báo phần bổ sung của lớp cơ sở và sau đó tiếp tục với lớp bên trong cụ thể cho tệp đó).

Cái gì đó như...

Scenegraph.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        //Scenegraph specific implementations
    }
}

DependentClass.cs:

namespace MyLib
{
    public partial class Scenegraph
    {
        public class DependentClass
        {
            //DependentClass specific implementations
        }
    }
}

Tôi nghĩ rằng đây là cách bạn có thể triển khai sạch sẽ các lớp bên trong trong khi không phải làm lộn xộn mọi thứ bên trong một tệp khổng lồ và lộn xộn.


2

Như những người khác đã nói, bạn nên tránh đặt tên một lớp giống với không gian tên của nó.

Dưới đây là một số gợi ý đặt tên bổ sung từ câu trả lời của svick cho câu hỏi liên quan "Tên cùng một lớp và không gian tên" trên Exchange Engineering Stack Exchange:

Bạn nói đúng rằng bạn không nên đặt tên không gian tên giống như kiểu mà nó chứa. Tôi nghĩ bạn có thể sử dụng một số cách tiếp cận:

  • Phân bổ: Model.DataSources.DataSource

Điều này đặc biệt hiệu quả nếu mục đích chính của không gian tên là chứa các kiểu kế thừa từ cùng một kiểu cơ sở hoặc triển khai cùng một giao diện.

  • Rút gọn: Model.QueryStorage

Nếu một vùng tên chỉ chứa một số lượng nhỏ các kiểu, có thể bạn không cần vùng tên đó.

  • Làm cho doanh nghiệp: Model.ProjectSystem.Project

Điều này có thể hoạt động đặc biệt đối với các tính năng là một phần quan trọng của sản phẩm của bạn, vì vậy chúng xứng đáng với tên riêng của chúng.

(Lưu ý rằng việc sử dụng câu trả lời ở trên Model.DataSource.DataSource, Model.QueryStorage.QueryStorage.Model.Project.Projectlàm ví dụ chứ không phải là MyLib.Scenegraph.Scenegraph.)

(Tôi cũng thấy các gợi ý đặt tên khác trong các câu trả lời khác ở đây hữu ích.)


1

Nó xảy ra khi nó là lớp chính của không gian tên. Vì vậy, đó là một động lực để đặt không gian tên trong thư viện, sau đó vấn đề sẽ biến mất nếu bạn thêm 'Lib' vào tên không gian tên ...

namespace SocketLib
{
    class Socket
    {
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.