none
Using Ref With Constructor On Derived Class RRS feed

  • Question

  • In VB.NET I can write code like the following:

    Friend MustInherit Class clsBase     
      Public Sub New(ByRef dsDataSet As DataSet)     
        ...     
      End Sub     
    End Class  
     
    Friend Class clsTest Inherits clsBase     
      Public Sub New(ByRef dsTest As TypedDataSets.Test)     
        MyBase.New(dsTest)     
      End Sub      
    End Class 

    The C# equivalent would seem to be:

    internal abstract class clsBase  
    {  
      public clsBase(ref DataSet dsDataSet)  
      {  
        ...  
      }  
    }  
     
    internal class clsTest: clsBase  
    {  
      public clsTest(ref TypedDataSets.Test dsTest): base(ref dsTest)  
      {  
      }  

    But this results in an error "cannot convert from 'ref TypedDataSets.dsTest' to 'ref System.Data.DataSet'" and attempts to cast dsTest as System.Data.DataSet rightfully result in "a ref or out argument must be an assignable variable."

    So my question is -- for this situation what is the correct way in C# to pass a reference type by reference in the constructor?  Or is this a situation where VB.NET can manage an implicit conversion that is not possible in C#?
    Thursday, March 26, 2009 7:02 PM

Answers

  • You can't do that in C#, but you could re-design your classes to something like this :

        class BaseData
        {
            public int BaseInt { get; set; }
        }

        class DerivedData : BaseData
        {
            public int DerivedInt { get; set; }
        }

        class Base
        {
            protected Base()
            {
            }

            public Base(ref BaseData data)
            {
                data = new BaseData();

                // extract rest of the initialization into Initialize
                Initialize(data);
            }

            protected void Initialize(BaseData data)
            {
                // This is the code originally in the base ctor
                data.BaseInt = 19;
            }
        }

        class Derived : Base
        {
            public Derived(ref DerivedData data)
            {
                data = new DerivedData();
                Initialize(data); // effectively doing a call to the base ctor
               
                // original derived initialization continues
                data.DerivedInt = 23;
            }
        }

    http://blog.voidnish.com
    Thursday, March 26, 2009 9:02 PM
    Moderator

All replies

  • Mark,
    Moving to C# is as you know more strict then VB and you have to start thinking in object oriented terms. Simply porting code over to C# may not be your answer. It may require re-engineering your classes. Just looking at your example gives me a feeling that this is not done correctly in the first place.
    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    Thursday, March 26, 2009 7:08 PM
  • I should add that the code in C# works if the objects are not passed by reference -- so C# will allow a derived class to be passed as an argument to a method in the base class, just not via a reference...

    Correction:  The second part of this statement should have read "-- so C# will allow a derived (read strongly typed) DataSet to be passed as an argument to a method requiring a DataSet, just not via a reference..."
    Thursday, March 26, 2009 7:32 PM
  • What is the class doing? What is its purpose?
    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    Thursday, March 26, 2009 7:34 PM
  • Mark Ledohowski said:

    I should add that the code in C# works if the objects are not passed by reference -- so C# will allow a derived class to be passed as an argument to a method in the base class, just not via a reference...



    It cannot pass an instance to the base class constructor in this scenario because there is no derived instance to pass yet.


    ...and I do not see yet how your posted code could work.  The message says you have an invalid cast.  What is the relationship between the two classes, if any?


    Mark the best replies as answers. "Fooling computers since 1971."
    Thursday, March 26, 2009 8:23 PM
    Moderator
  • The abstract class provides methods for instantiating and manipulating DataSets.  The concrete classes then merely implement a few properties to support these methods, while the code in the abstract class does the work.

    This architecture has been used on other projects and represents a proven mechanism that we are not interested in rearchitecting.  We are interested however in porting it over to a C# platform.  It seemed curious to me that both VB.NET and C# allow a derived (read strongly typed) DataSet to be passed to a method requiring a DataSet, but attempting to pass the same information via reference fails.

    I posed the initial question thinking that I am overlooking some syntactic element that is causing the statement to fail, and was wondering if someone in the community could point out my error, or alternatively confirm that this is an issue with language capabilities or language restrictions.
    Thursday, March 26, 2009 8:36 PM
  • Sorry Rudedog2, you caught a mistake I made when expressing the aside to the problem statement.  To clarify, there is an abstract class and a concrete class, and the abstract class has a constructor that accepts a DataSet while the concrete classes have constructors that accept a derived (read strongly typed) DataSet.

    This all works fine when the derived DataSets are passed in as straight objects, but fails when they are passed in via reference.
    Thursday, March 26, 2009 8:45 PM
  • You can't do that in C#, but you could re-design your classes to something like this :

        class BaseData
        {
            public int BaseInt { get; set; }
        }

        class DerivedData : BaseData
        {
            public int DerivedInt { get; set; }
        }

        class Base
        {
            protected Base()
            {
            }

            public Base(ref BaseData data)
            {
                data = new BaseData();

                // extract rest of the initialization into Initialize
                Initialize(data);
            }

            protected void Initialize(BaseData data)
            {
                // This is the code originally in the base ctor
                data.BaseInt = 19;
            }
        }

        class Derived : Base
        {
            public Derived(ref DerivedData data)
            {
                data = new DerivedData();
                Initialize(data); // effectively doing a call to the base ctor
               
                // original derived initialization continues
                data.DerivedInt = 23;
            }
        }

    http://blog.voidnish.com
    Thursday, March 26, 2009 9:02 PM
    Moderator
  • Thanks Nishant, this requires very little retooling to implement.  It becomes just a change to the constructors.
    Thursday, March 26, 2009 10:00 PM