2008-09-23 26 views
6

Ok, vì vậy tôi chỉ gặp phải vấn đề sau đã nhướn mày.Assembly.GetCallingAssembly() và các nhà thầu tĩnh?

Vì nhiều lý do tôi có thiết lập thử nghiệm trong đó các lớp Thử nghiệm trong TestingAssembly.dll phụ thuộc vào lớp TestBase trong tệp BaseTestingAssembly.dll. Một trong những điều các TestBase làm trong khi chờ đợi là tìm kiếm một nguồn lực nhất định trong nhúng riêng của mình và lắp ráp gọi

Vì vậy BaseTestingAssembly của tôi chứa đựng những dòng sau ...

public class TestBase {  
    private static Assembly _assembly; 
    private static Assembly _calling_assembly; 

    static TestBase() { 
    _assembly = Assembly.GetExecutingAssembly(); 
    _calling_assembly = Assembly.GetCallingAssembly(); 
    } 
} 

tĩnh kể từ khi tôi tìm , các hội đồng này sẽ giống nhau trong suốt vòng đời của ứng dụng, vậy tại sao phải tính toán lại chúng trên mọi thử nghiệm đơn lẻ.

Khi chạy điều này tuy nhiên tôi nhận thấy rằng cả hai _assembly và _calling_assembly đã được đặt thành BaseTestingAssembly thay vì BaseTestingAssembly và TestingAssembly tương ứng.

Đặt biến thành không tĩnh và khởi tạo chúng trong một hàm tạo thông thường đã sửa lỗi này nhưng tôi nhầm lẫn tại sao điều này lại xảy ra để bắt đầu việc này. Tôi nghĩ rằng các nhà xây dựng tĩnh chạy lần đầu tiên một thành viên tĩnh được tham chiếu. Điều này chỉ có thể là từ TestingAssembly của tôi mà sau đó nên có được người gọi. Có ai biết chuyện gì đã xảy ra không?

Trả lời

5

Các constructor tĩnh là được gọi bởi thời gian chạy và không trực tiếp bởi mã người dùng. Bạn có thể thấy điều này bằng cách thiết lập một breakpoint trong constructor và sau đó chạy trong trình gỡ lỗi. Hàm ngay phía trên nó trong chuỗi cuộc gọi là mã gốc.

Chỉnh sửa: Có rất nhiều cách để khởi tạo tĩnh chạy trong môi trường khác với mã người dùng khác. Một số cách khác là

  1. Họ đang ngầm bảo vệ chống lại điều kiện chủng tộc do đa luồng
  2. Bạn không thể bắt ngoại lệ từ bên ngoài initializer

Nói chung, nó có thể là tốt nhất không nên sử dụng chúng cho bất cứ điều gì quá phức tạp. Bạn có thể thực hiện đơn init với mẫu sau:

private static Assembly _assembly; 
private static Assembly Assembly { 
    get { 
    if (_assembly == null) _assembly = Assembly.GetExecutingAssembly(); 
    return _assembly; 
    } 
} 

private static Assembly _calling_assembly; 
private static Assembly CallingAssembly { 
    get { 
    if (_calling_assembly == null) _calling_assembly = Assembly.GetCallingAssembly(); 
    return _calling_assembly; 
    } 
} 

Add khóa nếu bạn mong đợi truy cập đa luồng.

+0

vậy tại sao hội đồng gọi điện không phải là rỗng? –

+0

Điều đó có hữu ích hơn không? :) –

+0

Không, có vẻ như điều đó sẽ có ý nghĩa mặc dù –

1

Tôi nghĩ câu trả lời nằm ở đây trong phần thảo luận của C# static constructors. đoán tốt nhất của tôi là các nhà xây dựng tĩnh được nhận được gọi là từ một bối cảnh bất ngờ vì:

Người dùng không có quyền kiểm soát trên khi constructor tĩnh được thực hiện trong chương trình

+0

Thực ra bạn có một số quyền kiểm soát :) – leppie

1

Assembly.GetCallingAssembly() chỉ cần trả về việc lắp ráp mục nhập thứ hai trong ngăn xếp cuộc gọi. Điều đó có thể rất phụ thuộc vào cách thức phương thức của bạn/getter/constructor được gọi. Đây là những gì tôi đã làm trong một thư viện để có được lắp ráp các phương pháp đầu tiên mà không có trong thư viện của tôi. (Điều này thậm chí làm việc trong các nhà xây dựng tĩnh.)

private static Assembly GetMyCallingAssembly() 
{ 
    Assembly me = Assembly.GetExecutingAssembly(); 

    StackTrace st = new StackTrace(false); 
    foreach (StackFrame frame in st.GetFrames()) 
    { 
    MethodBase m = frame.GetMethod(); 
    if (m != null && m.DeclaringType != null && m.DeclaringType.Assembly != me) 
     return m.DeclaringType.Assembly; 
    } 

    return null; 
} 
Các vấn đề liên quan