2009-03-01 34 views
16

Tôi muốn sử dụng một đối tượng trên AppDomains.Sử dụng thuộc tính [Serializable] hoặc subclassing từ MarshalByRefObject?

Đối với điều này tôi có thể sử dụng [Serializeable] thuộc tính:

[Serializable] 
class MyClass 
{ 
    public string GetSomeString() { return "someString" } 
} 

Hoặc lớp con từ MarshalByRefObject:

class MyClass: MarshalByRefObject 
{ 
    public string GetSomeString() { return "someString" } 
} 

Trong cả hai trường hợp tôi có thể sử dụng lớp như thế này:

AppDomain appDomain = AppDomain.CreateDomain("AppDomain"); 
MyClass myObject = (MyClass)appDomain.CreateInstanceAndUnwrap(
        typeof(MyClass).Assembly.FullName, 
        typeof(MyClass).FullName); 
Console.WriteLine(myObject.GetSomeString()); 

Tại sao cả hai cách tiếp cận dường như có cùng tác dụng? Sự khác biệt trong cả hai cách tiếp cận là gì? Khi nào tôi nên ưu tiên cách tiếp cận này qua phương pháp khác?

EDIT: Trên bề mặt tôi biết rằng có sự khác biệt giữa cả hai cơ chế, nhưng nếu ai đó nhảy ra khỏi bụi rậm và hỏi tôi câu hỏi tôi không thể trả lời đúng. Các câu hỏi là những câu hỏi khá cởi mở. Tôi hy vọng rằng ai đó có thể giải thích nó tốt hơn tôi có thể làm.

Trả lời

20

Sử dụng MarshallByRef sẽ thực thi các phương pháp của bạn trong AppDomain từ xa. Khi bạn sử dụng CreateInstanceAndUnwrap với một đối tượng Serializable, một bản sao của đối tượng được tạo cho AppDomain cục bộ, vì vậy bất kỳ cuộc gọi phương thức nào cũng sẽ được thực hiện trong AppDomain cục bộ.

Nếu những gì bạn muốn là liên lạc giữa AppDomains với phương thức MarshallByRef.

Một ví dụ:

using System; 
using System.Reflection; 

[Serializable] 
public class SerializableClass 
{ 
    public string WhatIsMyAppDomain() 
    { 
     return AppDomain.CurrentDomain.FriendlyName; 
    } 
} 

public class MarshallByRefClass : MarshalByRefObject 
{ 
    public string WhatIsMyAppDomain() 
    { 
     return AppDomain.CurrentDomain.FriendlyName; 
    } 
}  

class Test 
{ 

    static void Main(string[] args) 
    { 
     AppDomain ad = AppDomain.CreateDomain("OtherAppDomain"); 

     MarshallByRefClass marshall = (MarshallByRefClass)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "MarshallByRefClass"); 
     SerializableClass serializable = (SerializableClass)ad.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "SerializableClass"); 

     Console.WriteLine(marshall.WhatIsMyAppDomain()); 
     Console.WriteLine(serializable.WhatIsMyAppDomain()); 

    } 
} 

Mã này sẽ hiển thị "OtherAppDomain" khi bạn gọi WhatIsMyAppDomain từ đối tượng MarshallByRef, và tên AppDomain mặc định của bạn khi bạn gọi từ đối tượng Serializable.

5

Tại sao cả hai phương pháp đều có cùng tác dụng?

Họ làm không có cùng tác dụng.

Với MarshalByRefObject bạn đang tham chiếu một đối tượng qua ranh giới AppDomain. Với [Serializable] một bản sao của đối tượng đang được thực hiện. Điều này sẽ hiển thị nếu trạng thái của đối tượng được sửa đổi trong miền con và sau đó được kiểm tra lại (hoặc thực hiện Console.WriteLine bên trong AppDomain con).

+0

Ok ... đã thay đổi câu hỏi. Nó * có vẻ * vì cả hai cách tiếp cận đều có cùng tác dụng. –

2

MarshalByRefValueSerializable thực hiện các ngữ nghĩa khác nhau để truy cập từ xa/liên lạc qua AppDomain. MarshalByRefValue về cơ bản cung cấp cho bạn ngữ nghĩa tham chiếu thông qua đối tượng proxy, trong khi Serializable cung cấp cho bạn ngữ nghĩa giá trị (nghĩa là trạng thái của đối tượng được sao chép).

Nói cách khác, MarshalByRefValue sẽ cho phép bạn sửa đổi phiên bản trên các AppDomain khác nhau, trong khi Serializable sẽ không. Cái sau hữu ích khi bạn chỉ cần lấy thông tin từ một AppDomain này sang một AppDomain khác, ví dụ: để có được nội dung của một ngoại lệ từ một AppDomain khác.

+1

Vui lòng để lại nhận xét khi bỏ phiếu xuống. Cảm ơn. –

9

Các phương pháp này có các hiệu ứng khác nhau đáng kể.

Với phiên bản MarshalByRef bạn đang tạo 1 phiên bản đối tượng của mình. Nó sẽ sống trong AppDomain mới được tạo ra. Tất cả các accesse đối tượng được thực hiện thông qua một TransparentProxy.

Với phiên bản Serializable bạn đã tạo 2 trường hợp đối tượng của mình. Một được tạo trong AppDomain mới được tạo. Các cuộc gọi CreateInstanceAndUnwrap sau đó sẽ serialize đối tượng này và deserialize nó trong miền ứng dụng gốc. Điều này tạo ra một phiên bản thứ hai của đối tượng hoàn toàn độc lập với đối tượng đầu tiên. Trong thực tế, GC tiếp theo gần như chắc chắn sẽ loại bỏ đối tượng ban đầu và bạn sẽ bị bỏ lại với một cá thể.

+0

+1 cho liên kết đến mục blog hấp dẫn về TransparentProxy. Bài viết đó thực sự làm sáng tỏ MarshalByRefObject (MBRO) cho tôi. Bây giờ tôi chỉ tự hỏi cái quái gì là một Context và ContextBoundObject là :) – Qwertie

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