locked
Reference parameters must be initialized before they are passed to the method - really? The compiler doesn't enforce it. RRS feed

  • Question

  • User-1851576699 posted

    I am reading "Pro C# 5.0 and the .NET 4.5 Framework" by Andrew Troelsen. A very good book overall. Not without it's faults but what book isn't?

    In Chapter 4 of the book in the section entitled 'The ref Modifier' is the following bullet point about this C# feature:

    "Reference parameters must be initialized before they are passed to the method. The reason for this is that you are passing a reference to an existing variable. If you don't assign it to an initial value, that would be the equivalent of opearting on an unassigned local variable."

    I have declared methods that accept null references in the method signature and the compiler doesn't complain. When he says 'Reference parameters must be initialized' should that read 'It is strongly advised that you initialize your reference parameters before they are passed to the method."?

    The compiler doesn't complain about it. It doesn't get flagged as an error. The compiler, oddly enough, doesn't even give a warning about it. I am guessing he meant "should be" and not "must be". Words mean things and I can try and read between the lines but when you are learning things its not always black and white.

    Is the following code sample bad because it checks for null as the value of the 'ref' modifer parameter?

    class Person {
        public FirstName {get;set;}
        public LastName {get;set;}
        public Person Spouse; // cant declare as a property and use 'ref' modifier
    }
    
    public static void main(System.String[] args)
    {
        Person person1 = new Person();
        person1.FirstName = "John";
        person1.LastName = "Doe";
    
        GetASpouse(ref person1.Spouse);
    
        Console.WriteLine("{0} {1} is married to {2} {3}", 
            person1.FirstName, person1.LastName, person1.Spouse.FirstName, person1.Spouse.LastName);
    
    }
    
    private static void GetASpouse(ref Spouse s)
    { 
        
    
        if(s==null) {
            ApplicationDbContext ctx = new ApplicationDbContext();
            s = ctx.Spouses.FirstOrDefault(sp => sp.isSingle==true);
        }
    else {
    // do nothing, already have a spouse
    } }

    If the purpose of the C# 'ref' modifier is to modify a variable in the callers scope "why doesn't" the compiler enforce this and flag it as an error or at the very least a warning, like it does when using local variables without having initialized them. The behavior of the compiler seems inconsistent in this regard. Unless there is flexibility in the purpose of the 'ref' modifier other than as I have stated it above.

    Tuesday, May 20, 2014 11:13 AM

All replies

  • User465171450 posted

    The problem could be due to calling a static function within a static function though I'm not sure. This would also be the wrong way to go about it since the recommendation would be to return a new object and not be working on the variable referenced as that's more apt for collission in some circumstances.

    The compiler doesn't always complain about all things that are wrong. Sometimes it just can't look deep enough or through certain scenarios and there are plenty of instances where it can't throw errors on things until it's actually run. I would think though that this is a must case since, what would happen if you passed an un initialized variable to a ref parameter? The ref is passing the memory location of the variable, so what is the memory location of an uninitialized variable? Any attempt to access it blows up straight away in runtime. 

    Tuesday, May 20, 2014 11:09 PM
  • User-1851576699 posted

    But the example code I posted doesn't blow up because I am personally checking for null in the method that receives the 'ref' modifier parameter. I have ran examples. You can pass a null value in as an argument to a 'ref' modifier parameter. As long as you check for null in the method you are fine. Which, I do in the example.

    Wednesday, May 21, 2014 2:39 AM
  • User-1818759697 posted

    Hi,

    For this situation, you could refer to the following example:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string v1 = null; //If you use string v1; there would show an error;
                NullIf(ref v1);
                Console.WriteLine(v1);
    
                Person person1 = new Person();
                //person1.FirstName = "John";
                person1.LastName = "Doe";
    
                GetASpouse(ref person1.Spouse);
    
                if (person1.FirstName == null)
                {
                    person1.FirstName = "RestFirstName";
                }
    
                Console.WriteLine("{0} {1} is married to {2} {3}",
                    person1.FirstName, person1.LastName, person1.Spouse.FirstName, person1.Spouse.LastName);
                Console.ReadLine();
            }
    
            static void NullIf(ref string value)
            {
                if (value == "net")
                {
                    value = null;
                }
                else
                {
                    value = "Reset";
                }
            }
    
            private static void GetASpouse(ref Person s)
            {
    
    
                if (s == null)
                {
                    Person ss = new Person();
                    ss.FirstName = "ss";
                    ss.LastName = "ssLast";
                    s = ss;
                }
                else
                {
                    // do nothing, already have a spouse
                }
    
    
            }
    
        }
    
        
    
        class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public Person Spouse; // cant declare as a property and use 'ref' modifier
    
        }
    
    }
    

    If you use string v1 and not set a value, it would show an error. However, when you comment out the person1.FirstName and not set the person1.FirstName with a value, there is no error showing. This is because when you initialize the Person class, Person person1 = new Person();, the properties within the class has already been initialized. If you doesn't assign a value to the property, it would be null.

    For more information, you could also refer to:

    http://www.dotnetperls.com/ref

    http://stackoverflow.com/questions/135234/difference-between-ref-and-out-parameters-in-net

    Regards

    Wednesday, May 21, 2014 11:19 PM
  • User-1851576699 posted

    I am not sure what message you are trying to get across other than how to comply with the C# specification 'suggestion' that all reference variables be initialized before first use. Like many 'suggestions' in life it is left up to the programmer whether or not to follow this practice. If Microsoft didn't feel it was important enough to enforce wholeheartedly by way of a compiler error(or even a warning) then why should I? 

    The example you have offered doesn't seem to be much different than mine other than conforming to the C# specification suggestion by jumping through extra hoops.

    If the C# specification suggestion or recommendation was to ensure that a 'ref' parameter modifier points to 'something, anything for god sakes other than null' then they should have explicitly coded it that way. I for one prefer flexibility and power over conformance to a silly suggestion. If the programmer understands what he is doing than all is well. Any object that references a null value will throw an exception at runtime. So, re-iterating this recommendation before first use of a 'ref' modifier is really talking to hear one's own voice in my opinion.

    So I say again, parameters that are modified by the 'ref' keyword ARE NOT required to first having been initialized before being 'passed' because there is no one around to enforce that. They ARE however, required to having been initialized before 'first use' not unlike ANY OTHER reference in the C# language. Therefore, from what I can tell it is nothing more than a suggestion or recommendation.

    If anyone sees it differently please chime in. I am always to willing to see things in a clearer light. Maybe there is something I am missing.

    I have no real problem with the implementation. My only real question from the beginning was whether the 'so-called' requirement would be better understood as more of a suggestion or request.

    Microsoft knew what Microsoft was thinking when they wrote the C# language and the specification. I don't have the priviledge of knowing the full context of their decisions. Yes, I am making a big deal about the wording of the speicification but since words actually 'mean' things I feel it is worth the discussion.

    **EDIT**: I guess the compiler does actually enforce assignment of the 'ref' modifier arguments. I wasn't thinking of null as being a valid assignment. But it seems to be the case.

    Thursday, May 22, 2014 12:54 AM