Skip to main content
Skip table of contents

Client-Side C# Mapping for Interfaces

Proxy Interfaces

On the client side, a Slice interface maps to a C# interface with methods that correspond to the operations on that interface. Consider the following Slice interface:

SLICE
interface Simple
{
    ["cs:identifier:Op"]
    void op();
}

The Slice compiler generates the following definition for use by the client:

C#
public partial interface SimplePrx : Ice.ObjectPrx
{
    Task OpAsync(
        Dictionary<string, string>? context = null, 
        Progress<bool>? progress = null, 
        CancellationToken cancel = default);

    // Synchronous "overload" provided for backwards compatibility.
    void Op(Dictionary<string, string>? context = null);
}

As you can see, the compiler generates a proxy interfaceSimplePrx. In general, the generated name is <interface-name>Prx. If an interface is nested in a module M, the generated interface is part of namespace M, so the fully-qualified name is M.<interface-name>Prx.

In the client's address space, an instance of SimplePrx is the local ambassador for a remote instance of an Ice object that implements Simpleand is known as a proxy instance. All the details about the server-side object, such as its address, what protocol to use, and its object identity are encapsulated in that instance.

Creating a Proxy

For each Slice interface, apart from the proxy interface, the Slice-to-C# compiler creates a helper class: for an interface Simple, the name of the generated helper class is SimplePrxHelper.

This helper class provides the createProxy method. With our previous example:

C#
public class SimplePrxHelper : ...
{
    public static SimplePrx createProxy(
        Ice.Communicator communicator,
        string proxyString) { ... }
}

Use createProxy to create a proxy from a communicator and a “stringified” proxy:

C#
SimplerPrx simple = SimplePrxHelper.createProxy(
    communicator, "simple:tcp -h localhost -p 4061");

Inheritance from Ice.ObjectPrx

All generated proxy interfaces inherit directly or indirectly from the Ice.ObjectPrx interface, reflecting the fact that all Slice interfaces implicitly inherit from Object.

Interface Inheritance

Inheritance relationships among Slice interfaces are maintained in the generated C# classes. For example:

SLICE
module M
{
    interface A { ... }
    interface B { ... }
    interface C extends A, B { ... }
}

The generated code for CPrx reflects the inheritance hierarchy:

C#
namespace M;

public interface CPrx : APrx, BPrx
{
...
}

Given a proxy for C, a client can invoke any operation defined for interface C, as well as any operation inherited from C's base interfaces.

Casting a Proxy

In addition to createProxy, the generated helper class provides two static methods for converting a proxy into a proxy of another type:

C#
public class SimplePrxHelper : ...
{
    public static SimplePrx? uncheckedCast(Ice.ObjectPrx? proxy)

    public static async Task<SimplePrx?> checkedCastAsync(
        Ice.ObjectPrx proxy, 
        Dictionary<string, string>? context = null
        Progress<bool>? progress = null,
        CancellationToken cancel = default)
}

uncheckedCast

The helper’s uncheckedCast static method allows you to convert any proxy into the helper’s proxy type. For example:

C#
// Convert a SimplePrx into a WidgetPrx, even though the two types are unrelated.
WidgetPrx widget = WidgetPrxHelper.uncheckedCast(simple);

uncheckedCast is a local operation that always succeeds.

checkedCastAsync

checkedCastAsyncis a conditional cast of the proxy: this method makes a remote call to the target object to check if this object implements the proxy’s Slice interface. For example:

C#
// Call operation ice_isA on the Ice object to check if it implements Slice interface
// Widget.
WidgetPrx? widget = await WidgetPrxHelper.checkedCastAsync(simple);

If the target object implements the Slice interface, checkedCastAsyncreturns a non-null proxy, just like uncheckedCast. If the target object doesn’t implement this interface, checkedCastAsync returns null. checkedCastAsynccan also throw an exception, for example if it cannot reach the remote object.

The generated proxy helper also provides a synchronous overload: checkedCast. We recommend you always use async methods when making remote calls, and avoid these synchronous overloads provided for backwards compatibility.

While checkedCastAsync sounds safer than uncheckedCast (you’re making an additional check before casting), in practice you know or should know the type of your proxies and calling checkedCastAsync is rarely necessary.

Proxy Factory Methods

The base proxy interface ObjectPrx supports a variety of methods for customizing a proxy. Since proxies are immutable, each of these factory methods returns a copy of the original proxy that contains the desired modification. For example, you can obtain a proxy configured with a ten second invocation timeout as shown below:

C#
GreeterPrx greeter = GreeterPrxHelper.createProxy(...);

// Create a new GreeterPrx and assign it to greeter.
greeter = GreeterPrxHelper.uncheckedCast(greeter.ice_invocationTimeout(10000));

ice_invocationTimeout and other factory methods in C# return an Ice.ObjectPrx. You need to down-cast this proxy to the correct proxy type as shown above.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.