locked
VB to C# conversion: Generics RRS feed

  • Question

  • Could someone help me convert the following VB code to C#?  I've been struggling with this for way too long!

    Public Shared Function CreateClientInstance(Of T As Class)(ByVal host As String, ByVal servicePort As Integer) As T

    Thanks!

    Saturday, February 28, 2009 10:47 PM

Answers

All replies

  • Try the Instant converter.  It didn't puke on it.
    Saturday, February 28, 2009 11:30 PM
  • Are you referring to http://www.tangiblesoftwaresolutions.com?

    Their demo did work, thank you.
    Of -> where  got it!

    public static T CreateClientInstance<T>(string host, int servicePort) where T : class

    • Marked as answer by vze23c3q Sunday, March 1, 2009 12:16 AM
    Sunday, March 1, 2009 12:15 AM
  • public static T CreateClientInstance<T>( string host, int servicePort) where T: new()
    {
        ...
    }

    I'm assming the where T: new() as it need to create an instance of T which will require the new constraint
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Sunday, March 1, 2009 12:18 AM
  • Why do you require the constraint to a refernce type?
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Sunday, March 1, 2009 12:19 AM
  • Richard Blewett said:

    Why do you require the constraint to a refernce type?


    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2



    where T : new()

    It is needed for the JIT compiler, since the type in use will not be known runtime.  The JIT can only call a default parameterless constructor.  Including that constraint forces the developer to actually include one.  

    Similar stuff happens when deserializing referencing types.  A default parameterless constructor is called.  If you do not include one in the type definition, one is provided inline in the IL whenever the type instantiated.  But, the deserializer doesn't have that luxury.  Thus, the need to write out a public parameterless constructor.

    I think.  :)  I've been wrong a lot lately.

    Rudedog   =8^D
    Mark the best replies as answers. "Fooling computers since 1971."
    Sunday, March 1, 2009 12:47 AM
    Moderator
  • Here's the rest of the woking code (just playing with WCF):

            private static T CreateClientInstance<T>(System.ServiceModel.Channels.Binding binding, string host, int servicePort) where T : class  
            {  
                ClientBase<T> clientBase = null;  
                string uri = null;  
     
                uri = string.Format("{0}://{1}:{2}/{3}", binding.Scheme, host, servicePort, typeof(T).FullName);  
     
                //Create the class that will act as the proxy to the server  
                clientBase = (ClientBase<T>)(Activator.CreateInstance(typeof(ClientBase<T>), binding, new EndpointAddress(uri)));  
                return clientBase.ChannelFactory.CreateChannel();  
            }  
     
            static void Main(string[] args)  
            {  
                System.Diagnostics.Stopwatch t = new System.Diagnostics.Stopwatch();  
                string key = null;  
     
                _HttpService = CreateClientInstance<XtrFun.Shared.IXtrFun>(new WSHttpBinding(), "localhost", 35000);  
                _TcpService = CreateClientInstance<XtrFun.Shared.IXtrFun>(new NetTcpBinding(), "localhost", 35001);
             ...  
            {
     
    Sunday, March 1, 2009 1:16 AM
  • Hi RudeDog

    it was me that suggested the new() constraint as, as you say, the OP appears to need to create instance (based on the name of his method) so he would need the new() constaint to allow him to do this.

    The critical thing about generic compilation is that there is only one copy of the IL so the compiler has to unambiguously be able to generate that IL (thats why overloadable operators like == can;t be used in generic implementations). The new() constraint allows the compiler to assume that T has a default constructor and so can emit calls to it.

    As far as serialization is concerned, if you are talking about runtime serialization ([Serializable] and friends), no constructors are called on deserialization. It simply allocates the memory for the instance and then overwrites the fields (public and private) with the serialized data. The idea is its not trying to create a new instance, its trying to "restore" a saved instance. A constructor may cause side effects and so is not called

    However, it wasn't the new() constraint I was querying. The OP's solution looked like this:

    public static T CreateClientInstance<T>(string host, int servicePort) where T : class

    the T : class construct is saying that T must be a reference type. I was querying why this was necessary. The class and struct constraints are by far the most rarely used (I think I've used them in code once in 4-5 years) so I was interested in what the OP was doing that required them


    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Sunday, March 1, 2009 7:26 AM
  • Ahh ok makes sense as WCF contracts can only be classes and interfaces. Incidently (although this is OT for this forum) you appear to be jumping through hoops a bit there to generate the proxy

    Try this

    private static T CreateClientInstance<T>(Binding binding, string host, int servicePort) where T : class     
    {     
        string uri = null;     
        
        uri = string.Format("{0}://{1}:{2}/{3}", binding.Scheme, host, servicePort, typeof(T).FullName);     
        
        ChannelFactory<T> fact = new ChannelFactory<T>(binding, uri);  
        return fact.CreateChannel();  
    }    
     

    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Sunday, March 1, 2009 7:34 AM
  • vze23c3q said:

    Of -> where  got it!



    The 'As' portion of the VB generic specifier translates to the C# 'where' portion.  The type token(s) in the VB generic specifier translates to the '<T>' part in C#.  I think that this separation of the generic type tokens and the constraints is a slight design flaw in the C# language (but there aren't many).
    Convert between VB, C#, C++, Java, & Python (http://www.tangiblesoftwaresolutions.com)
    Sunday, March 1, 2009 3:14 PM
  • Richard, your description of DEserialization sounds more like the Serialization process.


    http://msdn.microsoft.com/en-us/library/system.runtime.serialization.aspx

    "Serialization is the process of converting an object or a graph of objects into a linear sequence of bytes for either storage or transmission to another location. Deserialization is the process of taking in stored information and recreating objects from it. "


    Every "deserialization" method in the FCL returns type object, AFIK.  "Recreating objects".  Doesn't that mean creating instances of types?  That implies that a class definition is required for deserialization, which it is.  Many times the deserialization process fails because of the lack of a default constructor, which is the only constructor that can be called.

    As for side effects, you are correct.  There can be side effects, like an improperly or incompletely constructed object.  Many complex objects require parameters in their constructors.  Deserialization cannot call overloaded constructors.  This is compensated for by implementing IDeserializationCallback, or applying an attribute to a method to finish or correct the object. 

    And the new() constraint doesn't allow the compiler to assume, rather it cause the compiler to enforce the presence of not just a default constructor but a public one at that.

    Rudedog   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."
    Sunday, March 1, 2009 9:25 PM
    Moderator
  • If you write the code and test this you will see that the default constructor isn't called on deserialization

    [Serializable]  
    class Person  
    {  
        public string Name { getset; }  
        public int Age { getset; }  
        public Person()  
        {  
            Console.WriteLine("created");  
        }  
    }  
          
    class App  
    {  
        static void Main(string[] args)  
        {  
            BinaryFormatter bf = new BinaryFormatter();  
            MemoryStream ms = new MemoryStream();  
            Person p = new Person { Name = "Rich", Age = 44 };  
     
            bf.Serialize(ms, p);  
     
            ms.Seek(0, SeekOrigin.Begin);  
     
            Person p2 = (Person)bf.Deserialize(ms);  
     
            Console.WriteLine("{0} is {1}", p2.Name, p2.Age);  
        }  

    Unless I missing something in what you are saying

    As far as new() is concerned we are really now violently agreeing just expressing it differently: "allows the compiler to assume" and "allows the compiler to enforce" are just two wayas of expressing the same thing. The compiler can call the default constructor ergo it must exist.
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Monday, March 2, 2009 8:21 AM
  • Okay,  I'm having a bad week.  Totally confused since the doctor visit.  This where my head was at....

    http://msdn.microsoft.com/en-us/library/ms182342(VS.80).aspx

    But, I swear I've classes that simply did not want to deserialize until I added a default constructor.
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 2, 2009 1:48 PM
    Moderator
  • Rudedog2 said:

    Okay,  I'm having a bad week.  Totally confused since the doctor visit.  This where my head was at....

    http://msdn.microsoft.com/en-us/library/ms182342(VS.80).aspx

    But, I swear I've classes that simply did not want to deserialize until I added a default constructor.


    Mark the best replies as answers. "Fooling computers since 1971."



    Ah!  Take a look at this sample, Richard.

    http://msdn.microsoft.com/en-us/library/58a18dwa(VS.80).aspx

    If you comment out the default constructor in the Employee class, deserialization fails!

    I've read somewhere where it is a bood practice to always include a defaut ctor if you wish to serialize the class.
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 2, 2009 1:55 PM
    Moderator
  • Yes,

    XmlSerializer requires a public default constructor and it runs in partial trust

    rutime serialization ([Serializable], etc) does not require a default constructor and does not run in partial trust
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Monday, March 2, 2009 2:07 PM
  • Richard Blewett said:

    Yes,

    XmlSerializer requires a public default constructor and it runs in partial trust

    rutime serialization ([Serializable], etc) does not require a default constructor and does not run in partial trust


    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2



    I just tried this...

    public Employee()  
            {  
                Console.WriteLine("Constructor called!");  
            } 

    ...and got no output to the console.
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 2, 2009 2:13 PM
    Moderator
  • Well "created" gets printed twice in this test

        public class Person  
        {  
            public string Name { getset; }  
            public int Age { getset; }  
            public Person()  
            {  
                Console.WriteLine("created");  
            }  
        }  
          
        class App  
        {  
            static void Main(string[] args)  
            {  
                XmlSerializer ser = new XmlSerializer(typeof(Person));  
                  
                MemoryStream ms = new MemoryStream();  
                Person p = new Person { Name = "Rich", Age = 44 };  
     
                ser.Serialize(ms, p);  
     
                ms.Seek(0, SeekOrigin.Begin);  
     
                Person p2 = (Person)ser.Deserialize(ms);  
                Console.WriteLine("{0} is {1}", p2.Name, p2.Age);  
            }  
        } 

    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Monday, March 2, 2009 2:25 PM
  • Curious.   I had used the sample where Employee is the type used in the serialized class, Employees.  Interesting.
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 2, 2009 2:55 PM
    Moderator
  • Can you posta compilable sample that shows your behavior? I can;t repro it
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Monday, March 2, 2009 3:14 PM
  • Richard Blewett said:

    Can you posta compilable sample that shows your behavior? I can;t repro it


    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2



    The link to the library.

    http://msdn.microsoft.com/en-us/library/58a18dwa(VS.80).aspx
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 2, 2009 4:39 PM
    Moderator
  • Well assuming all you did was add the Console.WriteLine in the Employee ctor and didn;t change the code anywhere else then of course you get no output. The code only serializes and it doesn;t use the default constructor when it creates the Employee, it uses a different ctor. Its the Deserialization that uses the default ctor
    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Monday, March 2, 2009 5:03 PM
  • Richard Blewett said:

    Well assuming all you did was add the Console.WriteLine in the Employee ctor and didn;t change the code anywhere else then of course you get no output. The code only serializes and it doesn;t use the default constructor when it creates the Employee, it uses a different ctor. Its the Deserialization that uses the default ctor


    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2



    Man!  I'm havin' a bad week.  Ever since the doctor zapped my retinas with the laser again on Tuesday.
    Mark the best replies as answers. "Fooling computers since 1971."
    Monday, March 2, 2009 7:35 PM
    Moderator