Ice for .NET supports two different mappings for Slice structures. By default, Slice structures map to C# structures if they (recursively) contain only value types. If a Slice structure (recursively) contains a string, proxy, class, sequence, or dictionary member, it maps to a C# class. A metadata directive allows you to force the mapping to a C# class for Slice structures that contain only value types.
In addition, for either mapping, you can control whether Slice data members are mapped to fields or to properties.
On this page:
Structure Mapping for Structures in C#
Consider the following structure:
This structure consists of only value types and so, by default, maps to a C# partial structure:
For each data member in the Slice definition, the C# structure contains a corresponding public data member of the same name.
The generated constructor accepts one argument for each structure member, in the order in which they are defined in the Slice definition. This allows you to construct and initialize a structure in a single statement:
The generated constructor calls the
ice_initialize partial method after initializing the struct data members. You can customize struct initialization by providing your own implementation of
ice_initialize. Note that C# does not allow a value type to declare a default constructor or to assign default values to data members.
The structure overrides the
Equals methods to allow you to use it as the key type of a dictionary. (Note that the static two-argument version of
Equals is inherited from
System.Object.) Two structures are equal if (recursively) all their data members are equal. Otherwise, they are not equal. For structures that contain reference types,
Equals performs a deep comparison; that is, reference types are compared for value equality, not reference equality.
Class Mapping for Structures in C#
The mapping for Slice structures to C# structures provides value semantics. Usually, this is appropriate, but there are situations where you may want to change this:
- If you use structures as members of a collection, each access to an element of the collection incurs the cost of boxing or unboxing. Depending on your situation, the performance penalty may be noticeable.
- On occasion, it is useful to be able to assign null to a structure, for example, to support "not there" semantics (such as when implementing parameters that are conceptually optional).
To allow you to choose the correct performance and functionality trade-off, the Slice-to-C# compiler provides an alternative mapping of structures to classes, for example:
"cs:class" metadata directive instructs the Slice-to-C# compiler to generate a mapping to a C# partial class for this structure. The generated code is almost identical, except that the keyword
struct is replaced by the keyword
class and that the class has a default constructor and inherits from
Some of the generated marshaling code differs for the class mapping of structures, but this is irrelevant to application code.
The class has a default constructor that initializes data members as follows:
|Data Member Type||Default Value|
The constructor won't explicitly initialize a data member if the default C# behavior for that type produces the desired results.
If you wish to ensure that data members of primitive and enumerated types are initialized to specific values, you can declare default values in your Slice definition. The default constructor initializes each of these data members to its declared value instead.
The class also provides a second constructor that has one parameter for each data member. This allows you to construct and initialize a class instance in a single statement:
All generated constructors call the
ice_initialize partial method after initializing the data members. You can customize class initialization by providing your own implementation of
Clone method performs a shallow memberwise copy, and the comparison methods have the usual semantics (they perform value comparison).
Note that you can influence the mapping for structures only at the point of definition of a structure, that is, for a particular structure type, you must decide whether you want to use the structure or the class mapping. (You cannot override the structure mapping elsewhere, for example, for individual structure members or operation parameters.)
As we mentioned previously, if a Slice structure (recursively) contains a member of reference type, it is automatically mapped to a C# class. (The compiler behaves as if you had explicitly specified the
"cs:class" metadata directive for the structure.)
Here is our Employee structure once more:
The structure contains two strings, which are reference types, so the Slice-to-C# compiler generates a C# class for this structure:
Property Mapping for Structures in C#
You can instruct the compiler to emit property definitions instead of public data members. For example:
"cs:property" metadata directive causes the compiler to generate a property for each Slice data member:
Note that the properties are non-virtual because C# structures cannot have virtual properties. However, if you apply the
"cs:property" directive to a structure that contains a member of reference type, or if you combine the
"cs:class" directives, the generated properties are virtual. For example:
This generates the following code: