Difference between revisions of "Zh/Documentation/DevGuide/ProUNO/CLI/Type Mappings"
| m | |||
| Line 7: | Line 7: | ||
| |NextPage=Zh/Documentation/DevGuide/ProUNO/CLI/Additional Structures | |NextPage=Zh/Documentation/DevGuide/ProUNO/CLI/Additional Structures | ||
| }} | }} | ||
| − | + | {{Documentation/DevGuideLanguages|Documentation/DevGuide/ProUNO/CLI/{{SUBPAGENAME}}}} | |
| {{DISPLAYTITLE:类型映射}} | {{DISPLAYTITLE:类型映射}} | ||
| __NOTOC__ | __NOTOC__ | ||
Revision as of 03:14, 14 May 2009
简单类型
简单类型按照下表进行映射。
| 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 和读取 Type 属性可能会更改实例的状态。因此,必须确保要同步处理并发的访问。默认构造 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框架动态创建代码过程中,通过显式定义参数(请参阅方法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).
  


