Type Mappings
Simple Types
Simple types are mapped according to the following table.
UNOIDL Type | CLI Framework class (namespace System) |
---|---|
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. In type declarations void
is only used as a return type.
2. Similar to UNOs com.sun.star.uno.TypeClass
there is a System.TypeCode
enumeration which, however, does not contain a value for void
.
any
The any
type will be mapped to a value type with the name uno.Any
. For example:
//UNOIDL
void func([in]any val);
//C#
virtual void func(uno.Any val);
Although a System.Object
can represent all types, it was decided to not use it, for the following reasons:
First, in UNO only, an interface can have no value, which amounts to a null reference in C# or a null pointer in C++. The any can represent all uno types and additionally knows a void state (com::sun::star::uno::TypeClass_VOID
). If the any
is mapped to System.Object
then a CLI null reference would represent both an interface with a null value and a void any
. This distinction is important.
Second, the any
can contain a particular interface. The consumer of the any knows exactly what type the any
contains because of the provided type information, and is spared to determine the type by using casts.
The function hasValue
determines if the type class is of TypeClass_VOID
, in other words, if the any carries a value. The Any class also overrides the methods, Equals
, ToString
and GetHashCode
from System.Object
. There is also an Equals
implementation which takes an Any
as argument. Hence the argument does not require unboxing as the overridden Equals
method does. The any offers a bunch of constructors. For complete initialization it needs a System.Type
and a System.Object
:
public Any(System.Type type, System.Object)
Because the type of an object can be identified by Object.GetType
, it is in some cases unnecessary to specify the type. Therefore there are also a couple of constructors, which only take the object as argument. For example:
public Any(char value) public Any(bool value)
However, when an UNO interface or struct is to be put in an Any
then the type must be explicitly provided, because structs can be derived and interface implementations can derive from multiple interfaces. Then Object.GetType
may then not return the intended type.
At this point the polymorphic structs needs to be mentioned in particular, because they currently require to provide a uno.PolymorphicType
in the Any constructor:
//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);
The Any contains a static member VOID which can be used whenever a void Any is needed:
//C#
obj.functionWithVoidAnyArgument(uno.Any.VOID);
The type and value contained in the Any
can be accessed by read-only properties named Type
and Value
. One can also subsequently assign new values by calling setValue
. This can be useful, when handling arrays. For example:
//C#
uno.Any[] ar = new uno.Any[1000];
foreach(uno.Any a in ar)
a.setValue(typeof(char), 's');
One could also construct new Any
instances and assign them:
foreach(uno.Any a in ar)
a = new uno.Any('c');
setValue
and the read access to the Type
property may change the state of the instance. Therefore one has to make sure that concurrent access is synchronized. When an Any
is default constructed, for example when creating an array of Any
s, then the member representing the Any
's type is null. Only when the Type
property is accessed and setValue
has not been called yet, then the type is set to void
. This setting of the member may interfere with setValue
, hence the need for synchronization. However, in most cases synchronization is not necessary.
The uno.Any
is contained in the cli_basetypes.dll
and the C# source file can be found in the cli_ure project (cli_ure/source/basetypes/uno/Any.cs
).
interface
General
UNOIDL interface types map to CTS interface types with public accessibility. If a UNO interface inherits an interface, then the target interface will do as well.
Methods
General
All methods have public accessibility. The method names and argument names of the target type are the same as the respective names in the UNOIDL declaration. The return type and argument types correspond to the mapping of the respective UNOIDL types. The order of the arguments is the same as in the UNOIDL declaration.
Types declared in a CLI language, do not need to provide argument names in methods. Only their types are required. If names are provided, then this is done for all arguments.
Exceptions, which are expressed by the raised keyword in UNOIDL, have no bearing on the target type. The IL assembler method head does not reflect the exception. However, metadata, which holds information about possible UNO exceptions, is available.
Parameter Types (in,out,in/out)
The CLI supports three kinds of parameter types: by-ref parameters, by-value parameters and typed-reference parameters. Typed-reference parameters are very special types and are of no relevance to this specification (for more information, see class System.TypedReference
). Within the CLR, objects are always passed as references. However, only objects that have a by-ref type, which is indicated by the trailing '&' in the type name, can be assigned a new value. Therefore, by-ref parameters can be used as in/out or just out parameters.
Parameters can have an in-attribute, out-attribute (CLI: InAttribute, OutAttribute) or both. They are generated in different ways:
- By using language-specific key words, such as out in C#, which produces an OutAttribute
- By using attribute classes, such as
System.Runtime.InteropServices.InAttribute
andSystem.Runtime.InteropServices.OutAttribute
- By explicitly defining parameters during dynamic code creation with the
System.Reflection.Emit
framework (see methodSystem.Reflection.Emit.MethodBuilder.DefineParameter
)
Parameter types are mapped as follows:
UNOIDL keyword | CIL parameter passing convention | CIL Custom Attributes |
---|---|---|
[in] | by-value | InAttribute |
[out] | by-ref | OutAttribute |
[inout] | by-ref | InAttribute, OutAttribute |
In metadata a "by-value" type is represented by a CLI build-in type or class name. A "by-ref" type additionally has an '&' appended. The InAttribute is represented by "[in]" and the OutAttribute by " [out]". If both attributes are applied, then a combination of both markers appears in the metadata. For example:
.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 { }
It depends on the language, what ways of parameter passings are supported. The language may also require a special syntax with dedicated keywords to mark a parameter to use a particular parameter passing convention. Therefore a general example cannot be provided. However, here are examples in C# and 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);
When one uses UNO types in a language that does not support the different parameter passings, then that language might not be suitable for programming UNO code. For example, JScript .NET does not support out parameters. Therefore it is inappropriate for most UNO applications.
A word about in-parameters. An UNOIDL in-parameter may not be changed from within the method. This could be expressed in C++ with a const modifier. For example:
//C++ .NET
void foo(const Foo& value);
The const modifier, however, is not supported by the CLI and has only a meaning in code written with the same language. For example, the C++ compiler creates an attribute, that will be evaluated by the same compiler but it is not guaranteed that other compilers make use of this attribute. For example:
//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
Since the C# compiler does not evaluate the IsConstModifier attribute, the argument could be modified in a C# implementation of that function.
A compiler could evaluate the InAttribute and prevent that the argument is changed. Since that is not required, in-parameters could be modified dependent on the language being used. Therefore, every developer must follow the rule:
Exceptions
CLI methods are not particularly marked if they throw exceptions. In ordner to not loose the information what exceptions can be thrown by a UNO interface method a custom attribute may be applied to that method. All exceptions which are indicated by the keyword raises in a UNOIDL interface description are mapped to a custom attribute, named uno.ExceptionAttribute
. One only need to use this attribute when one declares a new type in a CLI language. Otherwise it is only for informational purposes. The climaker tool from the cli language binding provides assemblies in which methods which throw exceptions (other than com.sun.star.uno.RuntimeException
) are tagged with this Attribute. If the attribute is not present a method can still throw a RuntimeException
or any other exception which is derived from it.
One-Way Methods
The UNOIDL oneway attribute has no counterpart in the CLI. To retain this information, the custom attribute uno.OnewayAttribute
is applied.
Attributes
The UNOIDL attribute type is mapped to a CTS property. The type of the property is the mapping of the type used in the attribute declaration in UNOIDL.
A UNOIDL readonly attribute is mapped to a read-only property. That is, the property only has a get method.
UNOIDL method attributes can throw exceptions. These are expressed by the custom attribute uno.ExceptionAttribute
which shall be applied to the get and/or set method. It shall only be applied if an exception is specified in UNOIDL.
XInterface
The CLI language binding does not support com.sun.star.uno.XInterface. Wherever a XInterface occurs in a UNOIDL method signature, the method in the mapping contains a System.Object
.
XInterface is used to control the lifetime of UNO objects. Since the CLR uses a garbage collection mechanism, similar to Java and Smalltalk, there is no need for an explicit control of an object's lifetime.
com.sun.star.uno.XInterface also provides a means to obtain other implemented interfaces by calling queryInterface. In CLI, code this is done by casting an object to the desired interface. If the object does not implement this interface, then a System.InvalidCastException
is thrown.
For the previously stated reasons, the XInterface adds no functionality to an implementation. Therefore, no mapping for this interface exists.
struct
A UNO IDL struct is mapped to CTS class type, which supports inheritance (that is, no sealed attribute in the class head). A struct, such as defined by the C# struct keyword, is a value type and therefore has no inheritance support. For example:
//C#
public struct Foo
{
}
IL class header:
.class public sequential ansi sealed beforefieldinit Foo extends [mscorlib]System.ValueType { }
Also, the class inherits System.Object
if the UNO struct has no base struct. Otherwise the target class inherits the class that is the mapping of the respective UNO base struct. Members of a UNOIDL struct are mapped to their respective target types. All members of the target type have public accessibility.
For ease of use, the target has two constructors: one default constructor without arguments and one that completely initializes the struct. The order of the arguments to the second constructor corresponds to the position of the members in the respective UNOIDL description. That is, the first argument initializes the member that is the mapping of the first member of the UNOIDL description. The names of the arguments are the same as the members that they initialize. Both constructors initialize their base class appropriately by calling a constructor of the base class. In some languages, instance constructor initializers are implicitly provided. For example, in C# base() does not need to be called in the initializer.
If a struct inherits another struct, the order of the arguments in a constructor is as follows: the arguments for the struct at the root come first, followed by the arguments for the deriving struct, and so on. The order of the arguments that initialize members of the same struct depends again on the position of the respective members within the UNOIDL declaration. The argument for the first member appears first, followed by the argument for the second member, and so on. The constructor calls the constructor of the inherited class and passes the respective arguments.
//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;
}
Polymorphic structs
As of OpenOffice.org 2.x, there is a new UNO IDL feature, the polymorphic struct. This struct is similar to C++ templates, in that the struct is parameterized and members can use the parameters as types. For example:
//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;
}
As one can see, the type that is provided by the parameter is a System.Object. When instantiating a polymorphic struct, one need not initialize the members that are Objects. They can be null.
const
If a UNOIDL const value is contained in a module rather then a constants group, then a class is generated with the name of the const value. The only member is the constant. For example:
// 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;
}
}
In contrast to the Java mapping, interfaces are not used, because interfaces with fields are not CLS compliant.
constants
A constants type is mapped to a class with the same name as the constants group. The namespace of the class reflects the UNOIDL module containing the constants type. For example:
//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 enumeration types map to a CTS enumeration. The target type must inherit System.Enum
and have the attribute sealed. For example:
//UNOIDL
enum Color
{
green,
red
};
//C#
public enum Color
{
green,
red
}
sequence
A UNOIDL sequence maps to a CTS array. The target type may only contain CLS types, which is always the case since this mapping specification only uses CLS types. The target array has exactly one dimension. Therefore a sequence that contains a sequence is mapped to an array that contains arrays. Those arrays are also called "jagged arrays". For example:
//UNOIDL
sequence<long> ar32;
sequence<sequence<long>> arar32;
//C#
int ar32;
int[] [] arar32;
exception
The com.sun.star.uno.Exception is mapped to an exception that uses the same namespace and name. All members have public accessibility. The target unoidl.com.sun.star.uno.Exception
inherits System.Exception
and has one member only, which represents the Context member of the UNOIDL Exception. The target type does not have a member that represents the Message member of the UNOIDL type. Instead, it uses the Message property of System.Object
.
For ease of use the target has two constructors: one default constructor without arguments and one that completely initializes the exception. The order of the arguments to the second constructor corresponds to the position of the members in the respective UNOIDL description. That is, the first argument initializes the member, which is the mapping of the first member of the UNOIDL description. The names of the arguments are the same as the members, which they initialize. Both constructors initialize their base class appropriately by calling a constructor of the base class. For example:
//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;
}
}
}
All UNO exceptions inherit com.sun.star.uno.Exception. Likewise their mappings also inherit from the unoidl.com.sun.star.uno.Exception
. The order of the constructor's arguments then depends on the inheritance chain. The arguments for the initialization of unoidl.com.sun.star.uno.Exception
come first followed by the arguments for the derived exception and so on. The order of the arguments, which initialize the members of the same exception, depends again from the position of the respective members within the UNOIDL declaration. The argument for the first member appears first, followed by the argument for the second member, and so on. The constructor calls the constructor of the inherited class and passes the respective arguments. For example, let us assume we have a exception FooException
which has two members:
//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;
}
}
}
services
For every single-interface-based service a CLI class is provided which enables typesafe instantiation of the service. For example, if there were a service com.sun.star.Test
then it could be created in these two way
//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);
If a service constructor method is specified to throw exceptions, then the respective CLI method hat the custom attribute uno.ExceptionAttribute
applied to it.
See chapter Services/Service Constructors under Data Types for further details.
singletons
Similar to the services there are CLI classes for new-style singletons. For example, if there were a singleton com.sun.star.TestSingleton then it could be created in these two ways:
//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). |