Search code examples
c#objectmethodsmonomonodevelop

Passing an object to a method results in an object with no values?


I am new to C# and I'm having a strange problem when I try to pass an object from one method into another. My problem is when I call for a value from the object in the second method it returns nothing.

Please forgive me if something like this has been asked before. All of my efforts have turned up hundreds of duplicate questions about the difference between normal operation and passing an object reference instead of simply passing the object. (I tried both ways and neither seem to work.)

Simply put, I couldn't find anything explaining why the value of my object would be empty when it gets passed to another method.

I've included an excerpt of how my classes are defined and what their methods do. I also included how this issue is implemented in my project. Finally, I've posted the output so you can see what I'm talking about (because I don't know enough to explain the problem very well, and it seems proper to show you the symptom first-hand).

How can I properly pass an object to another function? (ie: What am I doing wrong?)

Class Definitions:

// 'class Expression' stores an expression in postfix notation
// and does all kinds of sweet math stuffs to it:
public class Expresssion
{
    public List<string> Value;

    public Expression (List<string> postfix_input)
    {
        Value = postfix_input;
    }
    //(...)
}

// 'class Terp' is a static class designed to convert user-readable
// infix expressions into tokenized lists in postfix notation so I
// can more easily do math.
public static class Terp
{
    public static List<string> ToPostfix (string infix_input)
    {
        //{"1+2"} >> {"1","2","+"}
        return postfix_output;
    }
    public static string ToInfix (List<string> postfix_input)
    {
        //{"1","2","+"} >> {"1+2"}
        return infix_output;
    }
    public static string CompileString (List<string> tokens_input)
    {
        //{"1","2","+"} >> {"12+"}
        return string_output;
    }
    //(...)
}

Implementation:

public static void StepOne (string command, string user_input)
{
    // NOTE: 'command' and 'user_input' are both provided by parsing the
    // user's input via a graphical interface (I'm simplifying here because
    // I don't want this to get cluttered with regex stuff).

    // Creating the Expression instance:
    Expression target_expr = new Expression(Terp.ToPostfix(user_input));

    // Setting up console messages to make sure the input is there:
    Console.WriteLine("Command: '" + command + "'");
    Console.WriteLine("Expression: '" + Terp.CompileString(target_expr.Value) + "'");

    // Passing 'Expression' object into 'StepTwo()':
    StepTwo(command, target_expr);
}


static void StepTwo (string command, Expression target_expr)
{
    // Making sure everything made it through the Stargate alright:
    Console.WriteLine("------------------------------");
    Console.WriteLine("Command: '" + command + "'");
    Console.WriteLine("Expression: '" + Terp.CompileString(target_expr.Value) + "'");
}

Output:

Command: 'dd'
Expression: '12+'
------------------------------
Command: 'dd'
Expression: ''

As a final note, the 'Terp' class checks out. So does the 'Expression' class. Both behave splendidly in all other situations. After passing my object to StepTwo(), if I try to call target_expr.Value[0] my program throws an "argument out of range" exception.

Again, if anyone can explain what is wrong here I'd really appreciate it. I'm VERY new to C#, and figuring this one out has me pretty stumped.

Thanks in advance!

Update:

Sorry for the missing method. Here's the code for CompileString():

public static string CompileString (List<string> tokens_input)
    {
        string str = string.Empty;
        foreach (string token in tokens_input)
        {
            str = str + token;
        }
    return str;
    }

I don't see how that would change the value for target_expr, but I'm obviously missing something.


Solution

  • I totally solved my problem...

    I completely misunderstood how objects are handled in C#. I also didn't realize (though it's obvious to me now) a List<> is an object in C# instead of a simple data type (like it is with python).

    Answers (as always) could be found in documentation and in good articles about best practices (once I knew what to look for):

    The problem was in my methods ToInfix() and ToPostfix(). (Actually, the problem was with every method in the Terp class that handles conversion.)

    In short, I didn't realize that target_expr.Value was a reference to a list object. I also didn't realize that when I pass that object to a method, it passes a reference to the object (not a copy of its value) and that any changes effect the original object.

    Long story short, one of the methods in Terp "eats" the postfix_input list while it's converting from one form to the next. This garbled target_expr.Value.

    The solution was simple. When passing a List<> object to ToInfix(), I make a token-for-token copy before passing it on to any of the private methods in Terp:

    public static string ToInfix (List<string> postfix_input)
    {
        // Make a one-to-one copy of a list:
        List<string> postfix_copy = new List<string>();
        foreach (string token in postfix_input)
        {
            postfix_copy.Add(token);
        }
        // Then do stuff...
        //(...)
    }
    

    This fix makes everything behave as expected.

    Now that I know this is how objects work, I will go through and clean up Terp to make sure this is handled correctly. Thanks especially to @Shaharyar, since looking at his example got me on track, and @AlexD got me looking in the right place.

    Thank you all for your time!