C# Mapping for Classes
Class Mapping
A Slice class is mapped to a C# class with the same name. By default, the generated class contains a public field for each Slice field (just as for structures and exceptions). Alternatively, you can use the property mapping by specifying the "cs:property" metadata directive, which generates classes with properties instead of fields.
Consider the following class definition:
class TimeOfDay
{
["cs:identifier:Hour"]
short hour; // 0 - 23
["cs:identifier:Minute"]
short minute; // 0 - 59
["cs:identifier:Second"]
short second; // 0 - 59
["cs:identifier:TZ"]
string tz; // e.g. GMT, PST, EDT...
}
The Slice compiler generates the following code for this definition:
public partial class TimeOfDay : Ice.Value
{
public short Hour;
public short Minute;
public short Second;
public string TZ;
partial void ice_initialize();
public TimeOfDay()
{
...
ice_initialize();
}
public TimeOfDay(short Hour, short Minute, short Second, string TZ)
{
this.Hour = Hour;
this.Minute = Minute;
this.Second = Second;
this.TZ = TZ;
ice_initialize();
}
}
There are a number of things to note about the generated code:
The generated class
TimeOfDayinherits fromIce.Value. This means that all classes implicitly inherit fromValue, which is the ultimate ancestor of all classes.The generated class contains a public field for each Slice field.
The generated class has a primary constructor and a parameterless constructor.
Generated Constructors
All generated classes have a public parameterless constructor that initializes all fields using default values (see Fields). This constructor is used by the unmarshaling code. The unmarshaling code guarantees that all non-nullable fields receive a non-null value before the instance is returned to the application code.
The parameterless constructor initializes fields with certain types (sequence, dictionary, struct mapped to class) to null!. If you call this constructor, make sure to set these fields after construction.
A generated class also provides a primary constructor that accepts one argument for each field of the class. This allows you to create and initialize a class in a single statement, for example:
var tod = new TimeOfDay(14, 45, 00, "PST"); // 2:45pm
For a derived class, the constructor requires one argument for every field of the class, including inherited fields. For example, consider the definition from Class Inheritance once more:
class TimeOfDay
{
["cs:identifier:Hour"]
short hour; // 0 - 23
["cs:identitier:Minute"]
short minute; // 0 - 59
["cs:identifier:Second"]
short second; // 0 - 59
}
class DateTime extends TimeOfDay
{
["cs:identifier:Day"]
short day; // 1 - 31
["cs:identifier:Month"]
short month; // 1 - 12
["cs:identifier:Year"]
short year; // 1753 onwards
}
The Slice compiler generates the following constructors for these Slice classes:
public partial class TimeOfDay : Ice.Value
{
public short Hour;
public short Minute;
public short Second;
partial void ice_initialize();
public TimeOfDay()
{
ice_initialize();
}
public TimeOfDay(short Hour, short Minute, short Second)
{
this.Hour = Hour;
this.Minute = Minute;
this.Second = Second;
ice_initialize();
}
}
public partial class DateTime : TimeOfDay
{
public short Day;
public short Month;
public short Year;
partial void ice_initialize();
public DateTime()
{
ice_initialize();
}
public DateTime(
short Hour,
short Minute,
short Second,
short Day,
short Month,
short Year)
: base(Hour, Minute, Second)
{
this.Day = Day;
this.Month = Month;
this.Year = Year;
ice_initialize();
}
}
Property Mapping
You can instruct the compiler to emit property definitions instead of public fields. For example:
["cs:property"] class Point
{
["cs:identifier:X"]
double x;
["cs:identifier:Y"]
double y;
}
The "cs:property" metadata directive causes the compiler to generate a property for each Slice field:
public partial class Point : Ice.Value
{
public double X { get; set; }
public double Y { get; set; }
// ...
// same as without cs:property
}