C# Generics and TypeSupport

17 posts / 0 new
Last post
Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42
C# Generics and TypeSupport

I'm trying to write a Generic class for Topics that contains a participant, publisher, subscriber, dr, and dw.  I have the same class written and working in C++ as a Template and use code like:

auto dds_return_code = T::TypeSupport::register_type(domain_participant, T::TypeSupport::get_type_name());

and

topic_data_reader_ = T::DataReader::narrow(data_reader_);

 

what is the cooresponding code in C# generics?

 

T.TypeSupport is unresolved.  I'm missing something key.

 

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

related:

 

what is the C# equivalent of:

typename T::DataWriter * topic_data_writer;   // T is a topic

 

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

Hi Jay,

Our C++ API generics are not based on C++ templates, but on custom C/C++ generic code instantiated at compile time with define pre-processor statements.

The C# generated code is, in reality, C++/CLI code. I don't think it supports generics the way you may need it for what you're describing. But maybe there are other possible ways, could you share a foo example of the C# code structure you're trying to build?

Thanks,

Juanlu

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

what i have is a C++ template class that works.  It's 'T' is a topic.  Using T::TypeSupport, i can create a topic of type T.  I am trying to rewrite this class in C# using generics.  I understand that the rtiddsgen generated code is different but i'm not sure how.  I am not an expert in C# generics.  I was hoping I am just missing something there and that someone here has written a similar class, as it seems likely that this is a common approach.

When I try T.TypeSupport in C#, i do not have access in the same way i do in C++ with T::TypeSupport.

 

I can type up some of the code if needed.  The class is obviously not complete and not working, and it is on a different (offline) machine.  Before I do that, I'd like to confirm that I am making myself and the problem clear.

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

http://community.rti.com/kb/how-implement-generic-read-and-write-methods-using-cpp-templates

 

this doc lead us to the C++ template implementation.  Is the same trait support available for C# in the .NET api and generated code?

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

Hi Jay,

No, I believe those traits are not available in the C# implementation. You may be able to create a generic wrapper class anyway. But beware that C# generics are less powerful and expressive than C++ templates.

I think you could still create a wrapper class that is parameterised with the necessary types, this is, the data type class itself, the type support class and the Reader/Writer classes. Then internally perform creation operations and expose your necessary methods for sending/receiving samples. I'm just drafting here, but:

public class DDSSystemWrapper<T, TTypeSupport, TDataWriter, TDataReader>: DDS.DataReaderListener
{
    private TDataWriter _writer;
    private TDataReader _reader;
    public DDSSystemWrapper(DDS.DomainParticipant participant) { ... }
    public void writeSample(T sample) throws DDS.Retcode_Error { ... }
    public void on_data_available() { ... }
    ...
}

This is just an idea and I don't know if it serves your purpose, but it's just to show you how to use generics in C#. The constructor is responsible for creating the necessary DDS Entities. The class implements the DDS.DataReaderListener interface, so in the creation method, when calling create_datareader(), the class should install itself (this) as the listnerer for _reader. To register the type before creating the Reader or Writer you would call TTypeSupport.register_type(). The  on_data_available() method would need to do something generic with the samples, like put them in a generic collection or so. If you don't want this approach you can expose other types of methods for accessing your data (e.g. expose a method that returns a generic collection of type T).

In your application code, and after generating the necessary code with RTI DDS Gen, you should be able to do something like:

    DDSSystemWrapper<Foo, FooTypeSupport, FooDataWriter, FooDataReader> fooDDSSystem =
        new DDSSystemWrapper<Foo, FooTypeSupport, FooDataWriter, FooDataReader>(_domainParticipant);

    DDSSystemWrapper<MyAwesomeType, MyAwesomeTypeTypeSupport, MyAwesomeTypeDataWriter, MyAwesomeTypeDataReader> myAwesomeDDSSystem =
        new DDSSystemWrapper<MyAwesomeType, MyAwesomeTypeTypeSupport, MyAwesomeTypeDataWriter, MyAwesomeTypeDataReader>(_domainParticipant);

    ...

    try {
        fooDDSSystem.writeSample(fooData);
        myAwesomeDDSSystem.writeSample(myAwesomeSample); 
    catch (DDS.Retcode_Error e) { 
        // Catch DDS exception
    }

    ...

 I hope this helps clarifying and giving you ideas.

Thanks,

Juanlu

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

this definitely helps.  I'm working on implementing the class now(how you have proposed) and am having trouble using TTypeSupport.  I have no access to TTypeSupport.register_type() as you say and i do not know how to gain it. 

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

Hi Jay,

You will need to use generic type constraints like this:

public class DDSSystemWrapper<T, TTypeSupport, TDataWriter, TDataReader>
    where T : class, DDS.ICopyable<T>
    where TTypeSupport : DDS.AbstractTypedTypeSupport<T> 
    where TDataReader: DDS.TypedDataReader<T>
    where TDataWriter: DDS.TypedDataWriter<T>
{
    private TDataWriter _writer;
    private TDataReader _reader;
    public DDSSystemWrapper(DDS.DomainParticipant participant, TTypeSupport typeSupport, string typeName)
    {
        typeSupport.register_type_untyped(participant, typeName);
    }
}

Then you can declare your class like this (I used Shapes as the type) This compiles:

DDSSystemWrapper<ShapeType, ShapeTypeTypeSupport, ShapeTypeDataWriter, ShapeTypeDataReader> shapesWrapper = 
            new DDSSystemWrapper<ShapeType,ShapeTypeTypeSupport,ShapeTypeDataWriter,ShapeTypeDataReader>(
            participant, ShapeTypeTypeSupport.get_instance(), "ShapeTypeTypeName");

Let me know if this helps you.

Thanks,

Juanlu

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

that helps a lot.  that really shows me the difference between C++ templates and C# generics.  now, an easy one.  is typeName the same as the "topic" name?

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

It doesn't have to. The type name is a string that represents the registration name that you want to give to the type. The topic is just a name for a data stream. Like with Shapes Demo, different topics can use the same type name.

Beware that depending on the version of the product you're using, the type name has to be consistent across subsystems in order for them to be compatible. With X-Types, the concept of type name equality is only applies when type coercion is disallowed.

What version of the product are you using?

 

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

5.1

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

That version already incorporates X-Types. So the types have to be assignable in order to be compatible, when type coercion is allowed. Section 7.6.6 in the Core Libraries and Utilities User's Manual explains about type consistency.

Although it's usually a good idea to be consistent with type names, you could use different type names.

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

so i have this class or couple of classes done except for one thing.  i can't figure out how to "narrow" my datareader down to a typesafe version.

 

TDatareader has no narrow function.  i guess that means there is no "narrow" for the readers and writers in .NET as I don't see it in the api docs.

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

Hi Jay,

No, there is no narrow operation for C# DataWriters or DataReaders. The generated typed DataWriters and DataReaders effectively derive from DDS::TypedDataWriter and DDS::TypedDataWriter, which in turn inherit from DDS::DataWriter and DDS::DataReader.

C# generics are inherently type-safe. I think you can safely convert from one to the other inside the wrapping class.

Thanks,

Juanlu

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

do you see me having to pass in a DataSequence as well?

Offline
Last seen: 3 weeks 5 days ago
Joined: 01/15/2013
Posts: 90

Hi Jay,

You may have to. But you don't need to. Sequences are usually needed when you're going to perform bulk reads or takes. However, DDS provides APIs for taking a single sample or a single instance ( read_next_sample, read_next_instance, take_next_sample, take_next_instance). However, if you do need to add the sequence type, you can add a TSeq parameter to the generic class and you add the constraint TSeq : LoanableSequence<T>.

Hope this helps.

Offline
Last seen: 10 months 3 weeks ago
Joined: 10/18/2013
Posts: 42

that does help, thanks.