4 min read
Ice::Object and checked cast
Understand how to call and implement checked cast
The Ice::Object interface
With the Ice framework, all Ice interfaces implicitly derive from the Ice::Object interface, which provides four operations: ice_id, ice_ids, ice_ping and ice_isA.
The generated code implements these operations automatically. As an application developer using the Ice framework, you typically don't think about these built-in operations.
With IceRPC, the C# interfaces generated by the Ice compiler do not derive from any common base interface, and Ice::Object is just a regular Ice interface:
module Ice{ /// A sequence of strings representing Ice type IDs. sequence<string> TypeIdSeq;
/// Base interface with common operations. interface \Object { /// Gets the Ice type IDs of all the interfaces implemented by the target service. /// @return The Ice type IDs of all these interfaces, sorted alphabetically. idempotent TypeIdSeq ice_ids();
/// Tests whether the target service implements the specified interface. /// @param id The Ice type ID of the interface to test against. /// @return True when the target service implements this interface; otherwise, false. idempotent bool ice_isA(string id);
/// Pings the service. idempotent void ice_ping(); }}IceRPC does not provide the fourth operation, ice_id. A service can implement multiple Ice interfaces and does not always have a single most-derived Ice interface / type ID.
When you implement an Ice service with IceRPC, you decide if you want to implement this interface.
In C#, you implement Ice::Object like any other interface, except you don't need to actually implement any of the mapped interface methods. The IceRPC + Ice integration provides a default implementation for all these methods. For example:
using IceRpc;using IceRpc.Features;using IceRpc.Ice; // for IIceObjectService
[Service]internal partial class HelloService : IHelloService, IIceObjectService{ // IIceObjectService provides default implementations for all the ice_ operations.
public ValueTask SayHelloAsync(IFeatureCollection features, CancellationToken cancellationToken) { ... }}Checked cast
checkedCast is a helper method that calls the ice_isA operation on the proxy being "checked cast": it asks the target service (Ice object with Ice's terminology) if it implements a specific Ice interface. While this check is generally unnecessary (uncheckedCast works just as well), it used to be shown by all Ice demos and is therefore very common in existing code.
The net result is: if you reimplement an existing Ice server with IceRPC, your services need to implement Ice::Object when they are being "checked cast" by existing Ice client applications.
On the client-side, if you like checkedCast and want to keep check-casting your proxies, the IceRPC + Ice integration provides an equivalent API: AsAsync. The target service must implement Ice::Object; otherwise, AsAsync will fail with a DispatchException with status code NotImplemented.
Unchecked cast
You can convert a proxy into any other proxy type with the ToProxy extension method. For example:
IceObjectProxy objectProxy = // ... a plain Ice::Object proxy
// Convert objectProxy into a WidgetProxyWidgetProxy widgetProxy = objectProxy.ToProxy<WidgetProxy>();