On this page:
Basic C# Mapping for Classes
A Slice class is mapped to a C# class with the same name. By default, the generated class contains a public data member for each Slice data member (just as for structures and exceptions). Alternatively, you can use the property mapping by specifying the
"clr:property" metadata directive, which generates classes with virtual properties instead of data members.
Consider the following class definition:
The Slice compiler generates the following code for this definition:
There are a number of things to note about the generated code:
- The generated class
Ice.Value. This means that all classes implicitly inherit from
Value, which is the ultimate ancestor of all classes.
- The generated class contains a public member for each Slice data member.
- The generated class has a constructor that takes one argument for each data member, as well as a default constructor.
There is quite a bit to discuss here, so we will look at each item in turn.
Ice.Value in C#
Classes implicitly inherit from a common base class,
Value is a very simple base class with just a few methods:
Value methods behave as follows:
This function returns the actual run-time type ID for a class. If you call
ice_idthrough a reference to a base instance, the returned type id is the actual (possibly more derived) type ID of the instance.
The Ice run time invokes this function prior to marshaling the object's state, providing the opportunity for a subclass to validate its declared data members.
The Ice run time invokes this function after unmarshaling an object's state. A subclass typically overrides this function when it needs to perform additional initialization using the values of its declared data members.
This functions returns the
SlicedDataobject if the value has been sliced during un-marshaling or
This method returns a shallow member-wise copy of the value.
Note that the generated class does not override
Equals. This means that classes are compared using shallow reference equality, not value equality (as is used for structures).
Class Data Members in C#
By default, data members of classes are mapped exactly as for structures and exceptions: for each data member in the Slice definition, the generated class contains a corresponding public data member. Optional data members are mapped to instances of the
If you wish to restrict access to a data member, you can modify its visibility using the
protected metadata directive. The presence of this directive causes the Slice compiler to generate the data member with protected visibility. As a result, the member can be accessed only by the class itself or by one of its subclasses. For example, the
TimeOfDay class shown below has the
protected metadata directive applied to each of its data members:
The Slice compiler produces the following generated code for this definition:
For a class in which all of the data members are protected, the metadata directive can be applied to the class itself rather than to each member individually. For example, we can rewrite the
TimeOfDay class as follows:
If a protected data member also has the
clr:property directive, the generated property has protected visibility. Consider the
TimeOfDay class once again:
The effects of combining these two metadata directives are shown in the generated code below:
Refer to the structure mapping for more information on the property mapping for data members.
Class Operations in C#
Operations on classes are deprecated as of Ice 3.7. Skip this section unless you need to communicate with old applications that rely on this feature.
Operations in classes are not mapped at all into the corresponding C# class. The generated C# class is the same whether the Slice class has operations or not.
For a class that defines or inherits operations, the Slice-to-C# compiler generates instead a separate <
class-name>Disp_ class that can be used to implement an Ice object with these operations. Let's change our example to add a class operation:
The Slice compiler generates the following code:
Disp class is the skeleton class for this Slice class. Skeleton classes are described in the Server-Side C-Sharp Mapping for Interfaces.
Value Factories in C#
While value factories are necessary when using classes with operations (a now deprecated feature), value factories may be used for any kind of class and are not deprecated.
Value factories allow you to create classes derived from the C# classes generated by the Slice compiler, and tell the Ice run time to create instances of these classes when unmarshaling. For example, with the following simple interface:
The default behavior of the Ice run time will create and return an instance of the generated
If you wish, you can create your own custom derived class, and tell Ice to create and return these instances instead. For example:
You then create and register a value factory for your custom class with your Ice communicator:
Class Constructors in C#
A 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.
A class also provides a constructor that accepts one argument for each member of the class. This allows you to create and initialize a class in a single statement, for example:
For a derived class, the constructor requires one argument for every member of the class, including inherited members. For example, consider the the definition from Class Inheritance once more:
The Slice compiler generates the following constructors for these types:
If you want to instantiate and initialize a
DateTime instance, you must either use the default constructor or provide values for all of the data members of the instance, including data members of its base class.
For each optional data member of a class, the constructor accepts an
Ice.Optional parameter of the appropriate type. You can pass the value
Ice.Util.None as the value of any optional data member to initialize it to an unset condition.
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