2010-12-14 27 views
7

Tôi đã gặp một vấn đề lạ mà tôi vừa mới nhận thấy.Thừa kế mạng - Tự động phụ thuộc tham chiếu đến vấn đề hành vi

Nếu bạn có một giải pháp với 3 dự án

** NOTE Chỉnh sửa sau khi thảo luận ** Liba

dự án - Có một ClassA

namespace LibA 
{ 
    public class ClassA 
    { 
     public override string ToString() 
     { 
      return "The logic in class A!"; 
     } 
    } 
} 

Dự án LibB - Có một ClassB

using LibA; 

namespace LibB 
{ 
    public class ClassB 
    { 
     public ClassA a; 

     public ClassB() 
     { 
      a = new ClassA(); 
     } 

     public object Foo() 
     { 
      return a; 
     } 
    } 
} 

Dự án LibC - Có ClassC

using LibB; 

namespace LibC 
{ 
    public class ClassC 
    { 
     public ClassB b; 

     public ClassC() 
     { 
      b = new ClassB(); 
     } 

     public object Foo() 
     { 
      return b.Foo(); 
     } 
    } 
} 

Cuối cùng một người lái xe thử nghiệm

using System; 
using LibC; 

namespace Shell 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      ClassC c = new ClassC(); 
      Console.WriteLine(c.Foo()); 
     } 
    } 
} 

Bây giờ nếu bạn biên dịch này, mọi thứ sẽ hoạt động hoàn hảo. Nếu bạn kiểm tra nội dung của thư mục nhị phân của LibC, bạn sẽ thấy rằng nó tự động cuộn qua chuỗi phụ thuộc để xác định rằng nó cần phải kéo vào LibA và LibB

Tuy nhiên, nếu bạn thay đổi ClassB để kế thừa từ lớp A như

using LibA; 

namespace LibB 
{ 
    public class ClassB : ClassA 
    { 
     ClassA a; 
    } 
} 

nỗ lực để biên dịch, bạn sẽ nhận được lỗi

lỗi 2 các loại 'LibA.ClassA' được định nghĩa trong một hội đồng đó không được tham chiếu. Bạn phải thêm tham chiếu vào assembly 'LibA, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null'.

** Câu hỏi gốc **

Có ai biết tại sao (cho dù đó là msbuild hoặc visual studio) nó là đủ thông minh để tham khảo Liba khi ClassA thành viên của ClassB, nhưng nó không phải là thông minh đủ để tham chiếu LibA khi ClassA là lớp cơ sở của ClassB?

Tôi biết đó là nitpicky, nhưng tôi thực sự sẽ đánh giá cao một số hành vi nhất quán

** Câu hỏi sửa đổi với những thử nghiệm quan sát **

tôi nghe những gì một số định nghĩa là "trực tiếp" hay "gián tiếp" tài liệu tham khảo. Tuy nhiên, trực tiếp rõ ràng không chỉ là phạm vi khả năng hiển thị, nó có vẻ là thừa kế và sử dụng thực tế của một loại.

Không thừa kế, trình điều khiển thử nghiệm đủ thông minh để giải quyết và tự động tham chiếu LibA, LibB và LibC.

Có một số công khai thành viên ClassA hiển thị trong ClassB và chỉ riêng việc đó không tạo ra lỗi biên dịch/liên kết.

Trình gỡ lỗi chắc chắn giải quyết ClassA khỏi trình điều khiển thử nghiệm, do đó, nó tải rõ ràng lắp ráp chính xác.

Vì vậy, với tất cả những điều đó trong tâm trí. Tôi nhận được toàn bộ công cụ "trực tiếp" và "gián tiếp" ngay bây giờ.

Điều vẫn chưa nhấp vào tôi tại sao trình liên kết/trình biên dịch/IDE không ít nhất cố gắng tự động tham khảo các phụ thuộc của thư viện tham chiếu trong kịch bản "trực tiếp"? Rõ ràng là đủ thông minh để biết các phụ thuộc ở đó và tham khảo chúng trong một kịch bản "gián tiếp".

+0

thú vị .... +1 – RPM1984

+0

Chắc chắn thú vị nhất. Là một cựu anh chàng VB.NET, đây là điều tôi không thể hiểu được. Trình biên dịch VB.NET đủ thông minh để phụ thuộc chuỗi dự án; tại sao trình biên dịch C# lại không? – Crono

Trả lời

0

Tôi biết đó là nitpicky, nhưng tôi sẽ thực sự đánh giá cao một số quán hành vi

Đó là nhất quán. Bạn phải tham chiếu bất kỳ loại nào bạn sử dụng trực tiếp. Các tham chiếu gián tiếp được giải quyết một cách minh bạch.

+0

bạn đang xem xét một tham chiếu gián tiếp? Như bạn có thể thấy trong bản sửa đổi của lớp B, nó trực tiếp tham chiếu đến lớp A – Min

+0

Nhưng 'ClassC' không biết về' ClassA', do đó không cần tham khảo trực tiếp. ('ClassA' là một trường riêng của' ClassB', do đó không hiển thị với 'ClassC'). – Femaref

4

Đây là hành vi nhất quán. Cái đầu tiên là một tham chiếu đơn giản, cái thứ hai là thừa kế.

Nếu một assembly được biên dịch và một lớp kế thừa từ một lớp trong assembly khác, tham chiếu đó là cần thiết để xây dựng nó.

LibB chỉ chứa các thông tin mà là thêm trong định nghĩa lớp của ClassB, nó không sao chép mọi thứ, từ LibA (điều này sẽ sản xuất mã không phù hợp nếu LibA được cập nhật và ClassA được thay đổi trong khi làm điều đó, LibB sẽ vẫn chứa thông tin cũ).

Vì vậy, để sử dụng một định nghĩa lớp được thừa kế trong LibC, nó cần cả thông tin từ LibA (ví ClassA) và LibB (ClassB) để xây dựng nó, do đó một tham chiếu trực tiếp đến LibA là cần thiết.

Trong ví dụ, tất cả các tham chiếu đến các lớp khác nhau là riêng tư, do đó chỉ cấp tiếp theo được neeed (ClassC không cần biết về ClassA vì không có sử dụng trực tiếp của lớp đó). Nếu việc sử dụng ClassA trong ClassB là trường công khai hoặc nguyên mẫu, ClassC sẽ có tham chiếu trực tiếp đến ClassA và cũng cần tham chiếu trực tiếp đến định nghĩa lớp đó (tham chiếu đến LibA từ LibC).

Ở dạng khác, đây cũng là trường hợp trong ví dụ kế thừa. ClassC có tham chiếu trực tiếp đến ClassA (do ClassB nhập từ ClassA), do đó, tham chiếu đến cụm khai báo (cụ thể là LibA) là cần thiết để xây dựng định nghĩa lớp đầy đủ.

+0

Tôi hiểu lý do vì sao kế thừa cần thông tin. Tôi tự hỏi tại sao LibC tự động sao chép cả LibA và LibB, nếu nó là một thành viên và tại sao nó không tự động sao chép LibA và LibB nếu nó kế thừa – Min

+0

Vì trong trường hợp tham chiếu chỉ 'LibB' cần thông tin của' LibA' (lưu ý rằng trong mọi trường hợp, lớp được tham chiếu là một trường riêng nên không tiếp xúc với bên ngoài, vì vậy việc sử dụng các lớp không cần phải biết về nó). Tuy nhiên, trong trường hợp thừa kế, 'ClassB' vẫn là thành viên của' ClassC', nhưng 'ClassB' thừa kế' ClassA', do đó 'ClassC' cũng cần biết về' ClassA' (để xây dựng định nghĩa lớp đầy đủ). – Femaref

+0

Trên lưu ý này, tôi đã tiếp xúc ClassA dưới dạng biến công khai trong ClassB và nó vẫn tự động tham chiếu LibA trong LibC. Tuy nhiên, theo quan điểm của bạn, khi tôi đã cố gắng làm điều gì đó với biến công khai đó thì nó đã yêu cầu tham chiếu LibA một cách rõ ràng từ LibC. – Min

0

Trong trường hợp đầu tiên, bạn chỉ cần sử dụng ClassA. Vì vậy, nó không cần tài nguyên tại thời gian biên dịch, chỉ trong thời gian chạy.

Trong trường hợp thứ hai, bạn là kế thừa từ ClassA, do đó, định nghĩa và thông tin của nó là cần thiết bởi trình biên dịch để xây dựng hội đồng cuối cùng.

Trong trường hợp đầu tiên, VisualStudio sao chép DLL được tham chiếu vào thư mục đầu ra, bởi vì nó biết bạn sẽ cần nó ở đó.

Trong trường hợp thứ hai, VisualStudio không thêm tham chiếu vào dự án và tôi giả sử đó là nghi ngờ chính của bạn. Tôi đoán nó có nghĩa là theo cách đó để tránh các vấn đề bằng cách xâm nhập vào dự án của bạn. Nhưng, tôi chỉ đang đoán ...

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