Difference between revisions of "Zh/Documentation/DevGuide/ProUNO/CLI/Type Mappings"
m |
|||
Line 276: | Line 276: | ||
− | CLI 语言绑定不支持 <idl>com.sun.star.uno.XInterface<idl>。只要 UNOIDL 方法签名中出现 <idls>com.sun.star.uno.XInterface</idls> 映射中的方法就会包含 <code>System.Object</code>。 | + | CLI 语言绑定不支持 <idl>com.sun.star.uno.XInterface</idl>。只要 UNOIDL 方法签名中出现 <idls>com.sun.star.uno.XInterface</idls> 映射中的方法就会包含 <code>System.Object</code>。 |
Revision as of 03:43, 18 July 2008
简单类型
简单类型按照下表进行映射。
UNOIDL 类型 | CLI 框架类(名称空间系统) |
---|---|
boolean | Boolean |
byte | Byte |
short | Int16 |
long | Int32 |
hyper | Int64 |
unsigned short | UInt16 |
unsigned long | UInt32 |
unsigned hyper | UInt64 |
float | Single |
double | Double |
char | Char |
string | String |
type | Type |
void 1 | Void 2 |
1. 在类型声明中,void
仅用作返回类型。
2. 与 UNOs com.sun.star.uno.TypeClass
类似,存在一个 System.TypeCode
枚举,但该枚举不包含 void
值。
any
any
类型将被映射成名称为 uno.Any
的值类型。例如:
//UNOIDL void func([in]any val); //C# virtual void func(uno.Any val);
尽管 System.Object
可以表示所有类型,但是,由于以下原因,决定不予使用:
第一,只有在 UNO 中,接口才可以没有值,这相当于 C# 中的空引用或 C++ 中的空指针。any
可以表示所有 uno 类型且还可识别 void 状态 (com::sun::star::uno::TypeClass_VOID
)。如果将 any
映射成 System.Object
,则 CLI 空引用将同时表示值为空的接口和空的 any
。此区分很重要。
第二,any 可以包含特定的接口。any
的使用者根据提供的类型信息可以确切知道 any
包含的类型,从而不用再通过使用类型转换来确定类型。
函数 hasValue
确定类型是否为 TypeClass_VOID
,换句话说,确定 any 是否包含值。Any 类还可覆写 System.Object
的方法:Equals
、ToString
和 GetHashCode
。也存在将 Any 作为参数的 Equals 实现。因此,参数不会像覆盖 Equals 方法那样需要取出方法。any 提供许多构造函数。为了完全初始化,它需要 System.Type 和 System.Object:
public Any(System.Type type, System.Object)
由于对象的类型可以用 Object.GetType
标识,因此,在某些情况下,不需要指定类型。因此,也存在几个构造函数,它们仅将对象作为参数。例如:
public Any(char value) public Any(bool value)
但是,当将 UNO 接口或结构传入 Any
中时,由于结构和接口实现都可以从多个接口派生,因此必须显式提供类型。Object.GetType
则可能不会返回需要的类型。
此时,需要特别提到多态结构,因为它们当前需要在 Any 构造函数中提供 uno.PolymorphicType
:
//C# PolymorphicType t = PolymorphicType.GetType( typeof(unoidl.com.sun.star.beans.Optional), "unoidl.com.sun.star.beans.Optional<System.Char>"); Any a = new Any(t, objStruct);
Any 包含一个静态成员 VOID,无论何时需要空的 Any,都可以使用该成员:
//C# obj.functionWithVoidAnyArgument(uno.Any.VOID);
Any
中包含的类型和值可以通过名为 Type
和 Value
的只读属性进行访问。也可以随后通过调用 setValue
指定新值。当处理数组时,这可能非常有用。例如:
//C# uno.Any[] ar = new uno.Any[1000]; foreach(uno.Any a in ar) a.setValue(typeof(char), 's');
也可以构造新的 Any
实例并进行指定:
foreach(uno.Any a in ar) a = new uno.Any('c');
setValue
和读取 </code>Type</code> 属性可能会更改实例的状态。因此,必须确保要同步处理并发的访问。默认构造 Any
时,例如创建 Any
数组时,表示 Any
类型的成员则为空。只有当访问 Type
属性且尚未调用 setValue
时,类型才被设置为 void
。由于此成员设置可能会与 setValue
发生冲突,因此需要同步。但在大多数情况下不需要同步。
uno.Any
包含在 cli_basetypes.dll
中且可以在 cli_ure 项目(cli_ure/source/basetypes/uno/Any.cs
) 中找到 C# 源文件。
接口
接口概述
UNOIDL 接口类型映射成具有公共易用性的 CTS 接口类型。如果 UNO 接口继承某个接口,则目标接口也将继承该接口。
方法
方法概述
所有方法都具有公共易用性。目标类型的方法名称和参数名称与 UNOIDL 声明中的相应名称相同。返回类型和参数类型与各自的 UNOIDL 类型的映射相对应。参数顺序与 UNOIDL 声明中的参数顺序相同。
CLI 语言中声明的类型不需要在方法中提供参数名称。仅需要提供其类型。如果提供了名称,则会对所有参数都提供名称。
用 UNOIDL 中生成的关键字表达的异常与目标类型无关。IL 汇编程序方法头不会反映此异常。但是,可以使用包含可能的 UNO 异常相关信息的元数据。
参数类型(in,out,in/out)
CLI 支持三种参数类型:by-ref 参数、by-value 参数和 typed-reference 参数 Typed-reference 参数是非常特殊的类型,与此规范无关(如果需要更多信息,请参阅 System.TypedReference
)。在 CLR 中,对象始终作为参数传递。但是,只有类型为 by-ref 的对象(在类型名称中用后置 '&' 表示)才可以指定新值。因此,可以将 by-ref 参数用作 in/out 或 out 参数。
参数可以具有 in-attribute、out-attribute (CLI: InAttribute, OutAttribute) 或二者都具有。它们生成方法有所不同:
- 通过使用特定语言的关键字,如 C# 中的 out,可以生成 OutAttribute
- 通过使用属性类,如
System.Runtime.InteropServices.InAttribute
和System.Runtime.InteropServices.OutAttribute
- 在用
System.Reflection.Emit<code> 框架动态创建代码过程中,通过显式定义参数(请参阅方法 <code>System.Reflection.Emit.MethodBuilder.DefineParameter
)
参数类型映射如下:
UNOIDL 关键字 | CIL 参数传递约定 | CIL 自定义属性 |
---|---|---|
[in] | by-value | InAttribute |
[out] | by-ref | OutAttribute |
[inout] | by-ref | InAttribute, OutAttribute |
在元数据中,"by-value" 类型用 CLI 内置类型或类名表示。此外,"by-ref" 类型附加有 '&'。InAttribute 用 "[in]" 表示,OutAttribute 用 "[out]" 表示。如果同时应用这两个属性,则在元数据中将出现这两个标志的组合。例如:
.method public hidebysig newslot virtual abstract instance int16 func1([in] int16 'value') cil managed { } .method public hidebysig newslot virtual abstract instance int16 func2([out] int16& 'value') cil managed { } .method public hidebysig newslot virtual abstract instance int16 func3([out][in] int16& 'value') cil managed { }
这取决于语言及所支持的参数传递方式。语言还要使用特殊的语法,其中带有标记参数的专用关键字,以使用特定的参数传递约定。因此,无法提供一般示例。无论怎样,下面提供了 C# 和 C++ 中的示例:
//UNOIDL void foo1([in] short value); void foo2([out] short value); void foo3([inout] short value); // C# void foo1( short value); void foo2( out short value); void foo3( ref short value); // C++ .NET void foo( short value); void foo2( short *value); void foo3( short *value);
当在不支持不同参数传递的语言中使用 UNO 类型时,该语言可能不适用于 UNO 编程代码。例如,JScript .NET 不支持 out 参数。因此,不适合于大多数 UNO 应用程序。
关于 in-parameter 的解释。在方法中可能无法更改 UNOIDL in-parameter。这在 C++ 中可以用一个 const 修饰符来表示。例如:
//C++ .NET void foo(const Foo& value);
但是,CLI 不支持 const 修饰符,并且只有在用同一种语言编写的代码中才有意义。例如,C++ 编译器创建属性,由同一编译器分析该属性,但并不保证其他编译器也使用此属性。例如:
//C++ .NET void func(const Foo* a); // IL asm .method public hidebysig newslot virtual abstract instance void func(class Foo modopt([Microsoft.VisualC]Microsoft.VisualC.IsConstModifier) a) cil managed
由于 C# 编译器不分析 IsConstModifier 属性,因此,在该函数的 C# 实现中可以修改参数。
编译器可以分析 InAttribute 并防止更改参数。由于不要求必需使用 in-parameter,因此,可以根据所使用的语言来对它进行修改。因此,每个开发者都必须遵循以下规则:
异常
如果 CLI 方法抛出异常,则不会对其进行特殊标记。为了不破坏 UNO 接口方法所抛出异常的信息,可以将自定义属性应用于该方法。UNOIDL 接口说明中生成的关键字表示的所有异常都会被映射成名为 uno.ExceptionAttribute
. 的自定义属性。当用 CLI 语言声明新类型时,才需使用此属性。否则,仅用于参考。CLI 语言绑定中的 climaker 工具在抛出异常(不是 com.sun.star.uno.RuntimeException
) 的方法中提供汇编程序,这些方法标记有此
Attribute。如果不存在此属性,方法仍可以抛出 RuntimeException
或其派生的其他任何异常。
单向方法
在 CLI 中,没有与 UNOIDL 单向属性对应的属性。为了保留此信息,将应用自定义属性
uno.OnewayAttribute
。
属性
UNOIDL 属性类型被映射成 CTS 属性。属性类型是 UNOIDL 的属性声明中所使用类型的映射。
UNOIDL 只读属性将被映射成只读属性。也就是说,属性仅有 get 方法。
UNOIDL 方法属性可以抛出异常。这些异常用自定义属性 uno.ExceptionAttribute
表示,该属性将应用于 get 和/或 set 方法。如果 UNOIDL 中指定了异常,才会应用该属性。
XInterface
CLI 语言绑定不支持 com.sun.star.uno.XInterface。只要 UNOIDL 方法签名中出现 XInterface 映射中的方法就会包含 System.Object
。
XInterface 用于控制 UNO 对象的生存期。由于 CLR 使用垃圾收集机制(类似于 Java 和 Smalltalk),因此,无需显式控制对象的生存期。
通过调用 queryInterface,XInterface 还提供获取其他已实现接口的方法。在 CLI 代码中,可以通过将对象强制转换成所需的接口。如果对象不实现此接口,则会抛出 System.InvalidCastException
。
由于前面所述原因,XInterface 没有向实现添加任何功能。因此,不存在此接口的映射。
结构
UNO IDL 结构被映射成 CTS 类别类型,该类型支持继承(即类标题中无未知属性)。如 C# 结构关键字所定义,结构是一个值类型,因此,它不支持继承。例如:
//C# public struct Foo { }
IL 类标题:
.class public sequential ansi sealed beforefieldinit Foo extends [mscorlib]System.ValueType { }
此外,如果 UNO 结构没有基结构,则类将继承 System.Object
。否则,目标类要继承的类是对应 UNO 基结构的映射。UNOIDL 结构的成员被映射成其相应的目标类型。目标类型的所有成员都具有公共易用性。
为了方便使用,该目标有两个构造函数:一个是没有参数的默认构造函数,另一个可以完全初始化结构。第二个构造函数的参数顺序与相应的 UNOIDL 说明中的成员位置相对应。也就是说,第一个参数初始化 UNOIDL 说明中第一个成员所映射的成员。参数名称与它们初始化的成员名称相同。这两个构造函数都通过调用基类的构造函数来初始化其相应的基类。在某些语言中,会隐式提供实例构造函数初始化程序。例如,在初始化程序中不需要调用 C# base()。
如果某结构继承另一个结构,则构造函数中参数的顺序如下:首先是根的结构参数,其次是派生结构的参数,以此类推。初始化同一结构成员的参数顺序还取决于 UNOIDL 声明中各自成员的位置。首先出现的是第一个成员的参数,其次是第二个成员的参数,以此类推。构造函数调用所继承类的构造函数并传递各自的参数。
//UNOIDL struct FooBase { string s; }; struct Foo: FooBase { long l; }; // C# public class FooBase { public FooBase() // base() implicitly called{}public FooBase(string s) // base() implicitly { this.s = s; } public string s; }
public class Foo: FooBase { public Foo() { } public Foo(string s, int l): base(s) { this.l = l; } public int l; }
多态结构
从 OpenOffice.org 2.0 开始,新增加了 UNO IDL 功能:多态结构。此结构与 C++ 模板类似:可以对结构进行参数化,并且可以将成员用作类型。例如:
//UNO IDL struct PolyStruct<T> { T member; }; //C# public class PolyStruct { public PolyStruct() // base() implicitly called { } public PolyStruct(object theMember) { member = theMember; } public object member; }
可以看出,参数提供的类型为 System.Object。当实例化多态结构时,不需要初始化类型为 Object 的成员。它们可以为空。
const
如果 UNOIDL const 值包含在模块中而不是常数组中,则使用该 const 值的名称生成一个类。其中只有一个成员是常数。例如:
// UNO IDL module com { sun { star { foo { const long bar = 111; }; }; }; }; // C# representation of the mapping namespace unoidl.com.sun.star.foo { public class bar { public const int bar = 111; } }
与 Java 映射相比,由于 CLS 不支持带有字段的接口,因此没有使用接口。
constants
constants 类型被映射成与常数组同名的类。类的名称空间反映出了包含 constants 类型的 UNOIDL 模块。例如:
//UNOIDL module com { sun { star { foo { constants bar { const long a = 1; const long b = 2; }; }; // C# representationnamespace unoidl.com.sun.star.foo { public class bar { public const long a = 1; public const long b = 2; } }
enum
UNOIDL 枚举类型映射成 CTS 枚举。目标类型必须继承 System.Enum
并且具有密封的属性。例如:
//UNOIDL enum Color { green, red }; //C# public enum Color { green, red }
sequence
UNOIDL 序列映射成 CTS 数组。目标类型可以仅包含 CLS 类型,由于此映射规范仅使用 CLS 类型,因此,通常只包含 CLS 类型。目标数组实际上只有一维。因此,包含序列的序列被映射成包含数组的数组。这些数组又称为“交错数组”。例如:
//UNOIDL sequence<long> ar32; sequence<sequence<long>> arar32; //C# int ar32; int[] [] arar32;
异常
com.sun.star.uno.Exception 被映射成使用相同名称空间和名称的异常。所有成员都具有公共易用性。目标 unoidl.com.sun.star.uno.Exception
继承 System.Exception
且仅有一个成员,该成员用于表示 Exception 的 Context 成员。目标类型中没有成员可以表示 UNOIDL 类型的 Message 成员。而是使用 System.Object
的 Message 属性。
为了方便使用,该目标有两个构造函数:一个是没有参数的默认构造函数,另一个可以完全初始化异常。第二个构造函数的参数顺序与相应的 UNOIDL 说明中的成员位置相对应。也就是说,第一个参数初始化 UNOIDL 说明中第一个成员所映射的成员。参数名称与它们初始化的成员名称相同。这两个构造函数都通过调用基类的构造函数来初始化其相应的基类。例如:
//UNOIDL module com { sun { star { uno { exception Exception { string Message; com::sun::star::uno::XInterface Context; }; }; }; }; }; //C# namespace unoidl.com.sun.star.uno { public class Exception: System.Exception { public System.Object Context; public Exception(): base(){}public Exception(string Message, System.Object Context): base(Message) { this.Context = Context; } } }
所有 UNO 异常都继承 com.sun.star.uno.Exception。同样,其映射也从 unoidl.com.sun.star.uno.Exception
中继承。构造函数的参数顺序取决于继承链。首先是用于初始化 unoidl.com.sun.star.uno.Exception
的参数,其次是派生异常的参数,以此类推。初始化同一异常成员的参数顺序还取决于 UNOIDL 声明中各自成员的位置。首先出现的是第一个成员的参数,其次是第二个成员的参数,以此类推。构造函数调用所继承类的构造函数并传递各自的参数。例如,假设存在包括两个成员的异常 FooException
:
//UNOIDL module com { sun { star { uno { exception FooException: com::sun::star::uno::Exception { int value1; string value2; }; }; }; }; }; //C# namespace com.sun.star.uno { public class FooException: com.sun.star.uno.Exception { public int value1; public string value2; public FooException(): base() { } public FooException(string argMessage, System.Object Context, int value1, string value2): base(Message, Context) { this.value1 = value1; this.value2 = value2; } } }
服务
对于每个基于单接口的服务,都会提供一个可启用服务的类型安全实例化的 CLI 类。例如,如果存在服务 com.sun.star.Test
,则可以用两种方法创建该服务:
//C# // com.sun.star.Test implements interface XTest com.sun.star.uno.XComponentContext xContext = ...; object service= xContext.getServiceManager().createInstanceWithContext( "com.sun.star.Test", xContext ); XTest x = (XTest) service; // This is the new way XTest y = com.sun.star.Test.create(xContext);
如果指定服务构造函数方法来抛出异常,则相应的 CLI 方法就会对其应用自定义属性 uno.ExceptionAttribute
有关详细信息,请参阅 专业 UNO - API 概念 - 数据类型 中的“服务/服务构造函数”一章。
singletons
与服务类似,新式 singleton 也有 CLI 类。例如,如果存在一个 singleton com.sun.star.TestSingleton,则可以用以下两种方法创建该 singleton:
//C# com.sun.star.uno.XComponentContext xContext = ...; uno.Any a = xContext.getValueByName("com.sun.star.TestSingleton"); XTest x = (XTest) a.Value; //The alternative: XTest x = com.sun.star.TestSingleton.get(xContext);
Content on this page is licensed under the Public Documentation License (PDL). |