对于接口上的每个操作,代理类都有一个对应的同名成员函数。要调用某个操作,你要通过代理调用它。例如,下面给出的文件系统的部分定义 :
module Filesystem {
interface Node {
nonmutating string name();
};
// ...
};
name操作返回的是类型为 string 的值。假定我们有一个代理,指向的是Node 类型的对象,客户可以这样调用操作:
NodePrx node = ...; // Initialize proxy
string name = node.name(); // Get name via RPC
这是典型的返回值接收模式:对于复杂的类型,返回值通过引用返回,对于简单的类型 (比如 int或 double)则直接返回值。。
普通的、idempotent,以及nonmutating操作
你可以给 Slice 操作增加 idempotent 或nonmutating 限定符。就对应的代理方法的签名而言,idempotent或nonmutating没有任何效果。例如,考虑下面的接口:
interface Example {
string op1();
idempotent string op2();
nonmutating string op3();
};
这个接口的代理类是:
public interface ExamplePrx : Ice.ObjectPrx {
String op1();
String op2();
String op3();
}
因为idempotent和nonmutating影响的是调用分派(call dispatch )、而不是接口的某个方面,这三个方法看起来一样,是有道理的。
参数传递
in 参数
C# 映射的参数传递规则非常简单:参数或者通过值传递 (对于值类型),或者通过引用传递 (对于引用类型)。在语义上,这两种传递参数的方式是等价的:调用保证不会改变参数的值 (XREF 给出了一些警告)。
下面的接口有一些操作,会把各种类型的参数从客户传给服务器:
struct NumberAndString {
int x;
string str;
};
sequence<string> StringSeq;
dictionary<long, StringSeq> StringTable;
interface ClientToServer {
void op1(int i, float f, bool b, string s);
void op2(NumberAndString ns, StringSeq ss, StringTable st);
void op3(ClientToServer* proxy);
};
Slice 编译器为这个定义生成这样的代码:
public interface ClientToServerPrx : Ice.ObjectPrx {
public void op1(int i, float f, boolean b, String s);
public void op2(NumberAndString ns,
StringSeqss,
StringTable st);
public void op3(ClientToServerPrx proxy);
}
假定我们有一个代理,指向的是ClientToServer接口,客户代码可以这样传递参数:
ClientToServerPrx p = ...; // Get proxy...
p.op1(42, 3.14f, true, "Hello world!"); // Pass simple literals
int i = 42;
float f = 3.14f;
boolean b = true;
String s = "Hello world!";
p.op1(i, f, b, s); // Pass simple variables
NumberAndString ns = new NumberAndString();
ns.x = 42;
ns.str = "The Answer";
StringSS ss = new StringSS():
ss.Add(“hello world”);
StringTable st = new StringTable();
st[0] = ns;
st.put(new Long(0), ns);
p.op2(ns, ss, st); // Pass complex variables
p.op3(p); // Pass proxy
out 参数
slice out 参数直接映射成为C# out参数。
下面是我们在前面看到过的Slice定义,但所有的参数都是作为out 参数传递的:
struct NumberAndString {
int x;
string str;
};
sequence<string> StringSeq;
dictionary<long, StringSeq> StringTable;
interface ServerToClient {
void op1(out int i, out float f, out bool b, out string s);
void op2(out NumberAndString ns,
out StringSeq ss,
out StringTable st);
void op3(out ServerToClient* proxy);
};
Slice 编译器为这个定义生成了以下代码:
public interface ServerToClientPrx : Ice.ObjectPrx
{
void op1(out int i, out float f, out bool b, out string s);
void op2(out NumberAndString ns,
out StringSeq ss,
out StringTable st);
void op3(out ServerToClientPrx proxy);
}
假定我们有一个代理,指向的是 ServerToClient接口,客户代码可以这样传递参数:
ClientToServerPrx p = ...; // Get proxy...
int i;
float f;
bool b;
string s;
p.op1(out i, out f, out b, out s);
NumberAndString ns;
StringSeq ss;
StringTable st;
p.op2(out ns, out ss, out st);
ServerToClientPrx stc;
p.op3(out stc);
System.Console.WriteLine(i); // Show one of th
Null 参数
有些 Slice 类型自然地就有 “空”或 “不存在”语义。比如,C#序列(如果映射到CollectionBase)、字典,以及串和结构(如果映射到Class)都可以为null,但它们对应的slice定义却没有空值这个概念:
* Slice序列、字典、string不能为 null,但可以是空的。为了让这些类型的使用更容易,只要你把C# null 引用用作序列、字典、字符串的参数或返回值,Ice run time 都会自动把空的序列、字典、字符串发给接收者。
*当slice结构映射到C#类时,这时如果你传递一个空引用作来结构的参数或是返回值,ice run time自动将其转化为一个包含默认值的结构,这意味着所有代理成员都被初始为null,序列和字典成员被初始为空集合,字符串成员被初始化为空串,如果还有值类型的成员的,则会被初始化为它们对应的初始值。
作为一种方便的特性,这种行为很有用,特别是对于很深地嵌套的数据类型,其成员中的序列、字典,或字符串会自动作为空值到达接收端,例如,这样一来,在把一个大序列发送出去之前,你无需显式地初始化每一个串元素,也不会产生NullPointerExceptions。注意,以这种方式使用 null 参数并没有为序列、字典,或串创建null 语义。就对象模型而言,它们的 null 语义并不存在 (存在的只是空的序列、字典,以及串)。例如,不管你是通过null 引用、还是通过空串发送串,对接收者都没有区别;不管是哪种方式,接收者看到的都是空串。