這兩種方式的類一般都是用於遠程傳輸時使用的(原生我想不用討論了因為沒有區別)
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種情況:
- 序列化為XML格式:
在webservice裡,寫個web method,傳個自訂類做參數,就是這種情況。系統會幫你搞定,把自訂的類轉換為預設XML格式。
- 序列化為2進位:
要加[Serializable]標誌,可以把私人變數和公開變數都序列化。
- 序列化為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;
}