2012-01-07 25 views
6

nguồn khác nhau giải thích rằngTrộn MarshalByRefObject và Serializable

Khi một đối tượng có nguồn gốc hình thức MarshalByRefObject, một tham chiếu đối tượng sẽ được chuyển từ một miền ứng dụng khác chứ không phải là đối tượng riêng của mình. Khi một đối tượng được đánh dấu bằng [Serializable], đối tượng sẽ được tự động tuần tự, được chuyển từ một miền miền ứng dụng sang tên miền khác và sau đó được deserialized để tạo ra một bản sao chính xác của đối tượng trong miền ứng dụng thứ hai . Lưu ý sau đó rằng trong khi MarshalByRefObject chuyển tham chiếu, [Serializable] làm cho đối tượng được sao chép. [source]

Tôi đang thiết kế ứng dụng đầu tiên của tôi có sử dụng AppDomains và tôi đang tự hỏi điều gì sẽ xảy ra khi bạn đặt tham chiếu đến MarshalByRefObjects bên trong đối tượng serializable mà không thực hiện MarshalByRefObject, bởi vì cho đến nay tôi không thể tìm thấy bất kỳ tài liệu trên môn học-chủ đề, vấn đề.

Ví dụ: điều gì sẽ xảy ra nếu tôi cố trả lại List<MBR> trong đó MBR : MarshalByRefObject qua ranh giới AppDomain? Tôi có nhận được bản sao của List<MBR> trong đó mỗi MBR là một TransparentProxy đối với đối tượng gốc không? Và có bất kỳ tài liệu nào về các chi tiết kỹ thuật trộn lẫn hai cơ chế không?

Trả lời

7

tôi chỉ làm một thử nghiệm nhanh với List<MBR> và có vẻ như để làm việc như tôi đã hy vọng:

public class MBR : MarshalByRefObject 
{ 
    List<MBR> _list; 
    public MBR() { _list = new List<MBR> { this }; } 
    public IList<MBR> Test() { return _list; } 
    public int X { get; set; } 
} 

// Later... 
var mbr = AppDomainStarter.Start<MBR>(@"C:\Program Files", "test", null, true); 
var list = mbr.Test(); 
list[0].X = 42; 
list.Clear(); 
Debug.WriteLine(string.Format("X={0}, Count={1}", mbr.X, mbr.Test().Count)); 

Đầu ra là X=42, Count=1, và gỡ rối cho thấy List<MBR> chứa một __TransparentProxy. Vì vậy, rõ ràng, MarshalByRefObject được sắp xếp thành công bằng cách tham chiếu bên trong một đối tượng khác được so khớp theo giá trị.

Tôi vẫn muốn xem tài liệu hoặc chi tiết kỹ thuật nếu có ai đó có thể tìm thấy.

Đối với bất cứ ai là tò mò, tôi đã viết tiện dụng-dandy sandbox AppDomainStarter này:

/// <summary><see cref="AppDomainStarter.Start"/> starts an AppDomain.</summary> 
public static class AppDomainStarter 
{ 
    /// <summary>Creates a type in a new sandbox-friendly AppDomain.</summary> 
    /// <typeparam name="T">A trusted type derived MarshalByRefObject to create 
    /// in the new AppDomain. The constructor of this type must catch any 
    /// untrusted exceptions so that no untrusted exception can escape the new 
    /// AppDomain.</typeparam> 
    /// <param name="baseFolder">Value to use for AppDomainSetup.ApplicationBase. 
    /// The AppDomain will be able to use any assemblies in this folder.</param> 
    /// <param name="appDomainName">A friendly name for the AppDomain. MSDN 
    /// does not state whether or not the name must be unique.</param> 
    /// <param name="constructorArgs">Arguments to send to the constructor of T, 
    /// or null to call the default constructor. Do not send arguments of 
    /// untrusted types this way.</param> 
    /// <param name="partialTrust">Whether the new AppDomain should run in 
    /// partial-trust mode.</param> 
    /// <returns>A remote proxy to an instance of type T. You can call methods 
    /// of T and the calls will be marshalled across the AppDomain boundary.</returns> 
    public static T Start<T>(string baseFolder, string appDomainName, 
     object[] constructorArgs, bool partialTrust) 
     where T : MarshalByRefObject 
    { 
     // With help from http://msdn.microsoft.com/en-us/magazine/cc163701.aspx 
     AppDomainSetup setup = new AppDomainSetup(); 
     setup.ApplicationBase = baseFolder; 

     AppDomain newDomain; 
     if (partialTrust) { 
      var permSet = new PermissionSet(PermissionState.None); 
      permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); 
      permSet.AddPermission(new UIPermission(PermissionState.Unrestricted)); 
      newDomain = AppDomain.CreateDomain(appDomainName, null, setup, permSet); 
     } else { 
      newDomain = AppDomain.CreateDomain(appDomainName, null, setup); 
     } 
     return (T)Activator.CreateInstanceFrom(newDomain, 
      typeof(T).Assembly.ManifestModule.FullyQualifiedName, 
      typeof(T).FullName, false, 
      0, null, constructorArgs, null, null).Unwrap(); 
    } 
} 
0

Tôi hiểu rằng chỉ có đối tượng cấp cao nhất được thông qua có thể là MBR. Trong kịch bản của bạn, vì Danh sách không phải là MBR, khi Danh sách được chuyển qua ranh giới, bạn sẽ nhận được các bản sao được tuần tự hóa.

phần trong MSDN documentation này giải thích hành vi này:

MarshalByRefObject là lớp cơ sở cho các đối tượng giao tiếp qua các biên giới miền ứng dụng bằng cách trao đổi các thông điệp sử dụng một proxy. Các đối tượng không kế thừa từ MarshalByRefObject rõ ràng là nguyên soái theo giá trị. Khi một ứng dụng từ xa tham chiếu một nguyên soái của đối tượng giá trị, một bản sao của đối tượng được truyền qua các ranh giới miền ứng dụng.

Vì vậy, vì lớp (Danh sách) được chuyển không phải là MBR, nó sẽ được đăng, cùng với nội dung của nó.

Ngoài ra, trong khi không áp dụng trực tiếp vào câu hỏi, các hành vi sau đây là rất quan trọng cần lưu ý:

... các thành viên của đối tượng không phải là có thể sử dụng bên ngoài lĩnh vực ứng dụng mà họ đã tạo ra.

+0

Vì vậy, nếu MBR là không Serializable, sẽ có một ngoại lệ của một số loại khi .NET Framework cố gắng serialize nó ? Còn về mảng MBR [] thì sao? System.Array là Serializable, và không có nguồn gốc từ MarshalByRefObject. – Qwertie

+0

lại không thể tuần tự hóa: có, ngoại lệ sẽ xảy ra khi chạy. mảng MBR lại: Bạn có cùng vấn đề với Danh sách vì mảng là lớp cấp cao nhất. –

+2

Thử nghiệm cho thấy rằng một MBR không tuần tự hóa bên trong một container tuần tự được truyền qua tham chiếu mà không có ngoại lệ. –