Difference between revisions of "Zh/Documentation/DevGuide/ProUNO/CLI/Type Mappings"

From Apache OpenOffice Wiki
Jump to: navigation, search
m
Line 7: Line 7:
 
|NextPage=Zh/Documentation/DevGuide/ProUNO/CLI/Additional Structures
 
|NextPage=Zh/Documentation/DevGuide/ProUNO/CLI/Additional Structures
 
}}
 
}}
[[en:Documentation/DevGuide/ProUNO/CLI/Type Mappings]]
+
{{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 的方法:EqualsToStringGetHashCode。也存在将 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 中包含的类型和值可以通过名为 TypeValue 的只读属性进行访问。也可以随后通过调用 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.InAttributeSystem.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,因此,可以根据所使用的语言来对它进行修改。因此,每个开发者都必须遵循以下规则:

Documentation caution.png 即使语言允许,也无法在方法中修改 UNOIDL 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),因此,无需显式控制对象的生存期。


通过调用 queryInterfaceXInterface 还提供获取其他已实现接口的方法。在 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).
Personal tools
In other languages