呈顼I渝

remoting C# MarshalByRefObject 和Serializable的区别

 这两种方式的类一般都是用于远程传输时使用的(本机的我想不用讨论了因为没有区别)

marshalbyrefobject是通过引用传递serializable是通过值传递,现在就来分析下什么是引用传递,什么是值传递。

理解这个对Remoting或者webservice的认识是很重要的。

marshalbyrefobject(引用)本机或者是服务器上的其实都是同一个实例,只不过是服务器创建后你在本地使用了那个对象而已。比如说A类继承了marshalbyrefobject那么A类由服务器创建实例了,客户端都可以使用这个实例了。

现在我们假设A类有一个方法叫着A,Function返回值为一个string类型这个方法有一系列的操作。客户端在调用这个方法的时候只得到服务器返回的一个值,那个一系列的操作都将在服务器完成,这就是所谓的馊客服端。

Serializable(值类型)这个就不同了,假定我们刚才的那个A类的Funciton方法需要一个B类作为参数,B是一个可序列化的类,也 就是类的定义上面加了[Serializable()],如果没加那么这个方法将会报错。我们通过一个remoting的例子来解释一下

先写一个继承marshalbyrefobject的类

 public class HelloServer : MarshalByRefObject
    {
        public HelloServer()
        {            Console.WriteLine("HelloServer activated");        }


        public String HelloUserMethod(User user)
        {
            string title;
            if (user.Male)
                title = "先生";
            else
                title = "女士";

            Console.WriteLine( "Server Hello.HelloMethod : 你好,{0}{1}",  user.Name,title);

            return "你好," + user.Name + title;
        }

    }

再写一个可序列化的类

[Serializable]
 public class User
 {
  public User(string name,bool male)
  {
            this.name = name;
            this.male = male;
  }
  string name="";
  bool male=true;
  public string Name
  {
   get{return name;}
   set{name = value;}
  }
  public bool Male
  {
   get{return male;}
   set{male = value;}
  }

 }

现在我们将在服务端和客户端使用它们。

服务端如下:

 public class Server
 {
  public static int Main(string [] args)
  {

   TcpChannel chan1 = new TcpChannel(8085);
   HttpChannel chan2 = new HttpChannel(8086);

   ChannelServices.RegisterChannel(chan1);
   ChannelServices.RegisterChannel(chan2);


RemotingConfiguration.RegisterWellKnownServiceType (typeof(HelloServer), "SayHello", WellKnownObjectMode.Singleton);   //创建类的实例

   System.Console.WriteLine("Press Enter key to exit");
   System.Console.ReadLine();
   return 0;
  }

客户端如下:

public class Client
 {
        public static void Main(string[] args)
        {
          //使用HTTP通道得到远程对象
            HttpChannel chan2 = new HttpChannel();
            ChannelServices.RegisterChannel(chan2);
            HelloServer obj1 = (HelloServer)Activator.GetObject(
                typeof(RemotingSamples.HelloServer),
                "http://localhost:8086/SayHello");//创建类的实例
            if (obj1 == null)
            {
                System.Console.WriteLine(
                    "Could not locate HTTP server");
            }
            Console.WriteLine(
                "Client1 TCP HelloUserMethod {0}",
                obj1.HelloUserMethod(new User("张生",true))); //将类作为参数
(将User作为参数必须是serializable)                   }

 }

 }

从MarshalByRefObject派生的类和有[Serializable]的类都可以跨越应用程序域作为参数传递。
从MarshalByRefObject派生的类按引用封送,有[Serializable]标志的类,按值封送。
如果此类即从MarshalByRefObject派生,也有[Serializable]标志也是按引用封送。

序列化有3种情况:

  1. 序列化为XML格式:
    在webservice里,写个web method,传个自定义类做参数,就是这种情况。系统会帮你搞定,把自定义的类转换为默认XML格式。
  2. 序列化为2进制:
    要加[Serializable]标志,可以把私有变量和公共变量都序列化。
  3. 序列化为soap格式:
    需要实现ISerializable接口,定义序列化函数ISerializable.GetObjectData,和还原序列化的构造函数。
    一个soap参数类的sample:
[Serializable]
    
public class serialze:ISerializable
    
{
        
// 序列化函数,由 SoapFormatter 在序列化过程中调用
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext
             ctxt)
        
{
            
// 向 SerializationInfo 对象中添加每个字段
             info.AddValue("UserName", UserName);
             info.AddValue(
"UserID",UserID);
         }


        
// 还原序列化构造函数,由 SoapFormatter 在还原序列化过程中调用
        public serialze(SerializationInfo info, StreamingContext ctxt)
        
{
            
// 从 SerializationInfo 对象中还原序列化出各个字段
             UserName = (string)info.GetValue("UserName", typeof(string));
             UserID
= (int) info.GetValue("UserID",typeof(int));
         }

  
        
public serialze()
        
{}

        
public string UserName;
        
public int UserID;
     }

posted on 2011-07-30 17:14  呈顼  阅读(1636)  评论(2编辑  收藏  举报

导航