0

I am coming from JavaScript and trying to better understand working with object in C#. I have some simple code:

class Program
{
    static void Main(string[] args)
    {
        MyClass firstObj = new MyClass();
        firstObj.Number = 6;
        Console.WriteLine(firstObj.Number);

        object secondObj = doResults();
        string getString = secondObj.GetType().GetProperty("resultsString").GetValue(secondObj).ToString();
        Console.WriteLine(getString);

        Console.ReadLine();
    }

    public static object doResults()
    {
        ResultsObj newResults = new ResultsObj();
        newResults.resultsString = "Here is my string";

        return newResults;
    }

}

public class MyClass
{
    public int Number { get; set; }
}

public class ResultsObj
{
    public string resultsString { get; set; }
}

In the first part of Main(), I create an object, add a property, set a value and then access and display that value. Its all pretty straight forward.

In the second part of Main(), I call the doResults() method, which creates an object a string property.

My questions is this line:

string getString = secondObj.GetType().GetProperty("resultsString").GetValue(secondObj).ToString();

It seems so involved to me. Is that really the proper/most efficient way to access the properties of the returned object?

I think I can code
  • 647
  • 1
  • 6
  • 18

5 Answers5

9

The fundamental difference between C# and JavaScript is that C# is a strongly-typed language. In your main method you did not "add a property", you set the value of an existing property. The reason you're having so much trouble is that your reference variable is not of the correct type.

A type is a collection of properties and methods (a blueprint) for an object instance. This is similar to JavaScript except that in JavaScript you can add properties and methods at run-time and in C# you cannot, you are limited to what is available when the code is written (except for ExpandoObject which is a more advanced concept). The compiler will only let you access the properties and methods that are defined by the type of the variable being used to make that reference. When you return object from your method you are saying "the caller of this method can only access the properties and methods of an object".

So basically you need to decide what properties and methods you want the consumer to be able to access (i.e. the type). In this case your method creates an instance of ResultsObj and returns it, so the return type should be defined as ResultsObj.

public static ResultsObj doResults()
{
    ResultsObj newResults = new ResultsObj();
    newResults.resultsString = "Here is my string";

    return newResults;
}

Now your calling code knows that what is it getting back is a ResultsObj can can access the properties and methods of that type.

ResultsObj secondObj = doResults();
Console.WriteLine(secondObj.resultsString);

It all comes down to types. To reiterate, the compiler is only going to let you access properties and methods of the type defined by the reference variable.

BTW, you could also write the second block of code as:

var secondObj = doResults();
Console.WriteLine(secondObj.resultsString);

This may seem confusing, especially coming from a JavaScript background where var means something different. In this case C# is doing implicit typing. Because the method doResults() is defined as returning a ResultsObj the variable secondObj is implicitly typed as such. If you tried to write the following code it would not compile because the implicit typing already decided that secondObj was a ResultObj and you cannot assign a number to a variable of type ResultsObj.

var secondObj = doResults();
secondObj = 1; // This would cause a compiler error
Craig W.
  • 17,838
  • 6
  • 49
  • 82
  • ... and if you want to actually add properties, you should look into `dynamic` or [`ExpandoObject`](http://stackoverflow.com/q/1653046/11683). – GSerg Oct 30 '15 at 14:01
  • While var is an option and does work, I find it better to use the actual object type (in this case ResultsObj) instead of var. This makes the code more readable by a human trying to come in later or who didn't originally write it. Otherwise they must go to the doResults() definition to find out what its returning. – Wolfie Oct 30 '15 at 14:33
  • @Wolfie: I think the use of `var` is a personal choice. I happen to prefer it. I do all my development in Visual Studio so I just have to hover over `doResults()` to find out the return type and Intellisense gives me all the available properties and methods so for the most part I really don't care a lot about the type, I just care what properties/methods I can access. Use what you want, there is no right or wrong. – Craig W. Oct 30 '15 at 14:37
5

No, using reflection is for sure not the most efficient way. But more important, it's also not the most readable way. Write compile-time type-safe code.

Instead of returning Object you should return the right type ResultsObj:

public static ResultsObj doResults()
{
    ResultsObj newResults = new ResultsObj();
    newResults.resultsString = "Here is my string";

    return newResults;
}

then it's easy, readable, safe and efficient:

ResultsObj secondObj = doResults();
string getString = secondObj.resultsString;

If you can't change the type and you have to use Object you can cast it to the right type:

object secondObj = doResults();
ResultsObj resultObj = (ResultsObj) secondObj;
string getString = resultObj.resultsString;
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
3

In C# we have type safety so use it whenever you can. So instead of returning an object, return the type you are using, for example:

public static ResultsObj doResults()
{
    ResultsObj newResults = new ResultsObj();
    newResults.resultsString = "Here is my string";

    return newResults;
}

Then you use it like this:

ResultsObj secondObj = doResults();
secondObj.resultsString = "blah";

Another alternative (and I only mention here because it can be useful in certain circumstances, so don't code like this by default) is to use the type dynamic. This removes all type checking but means you need to be careful about your code:

dynamic secondObj = doResults();
secondObj.resultsString = "blah"; //this will work
secondObj.NonExistantProperty = "blah"; //this will compile but fail at runtime
DavidG
  • 113,891
  • 12
  • 217
  • 223
  • Might be worth noting that `dynamic` also means Intellisense won't work, so its very easy to get typo's and casing issues that won't come up until runtime. – Ron Beyer Oct 30 '15 at 14:06
3

1.Return a ResultsObj and not just an object:

public static ResultsObj doResults()
{
    ResultsObj newResults = new ResultsObj();
    newResults.resultsString = "Here is my string";

    return newResults;
}

2.call the method with a correct left hand side:

ResultsObj res = doResults();
Console.Write(res.resultsString);

P.S.: The left hand side can be var(compiler feature) like in js:

var res = doResults(); 
Console.Write(res.resultsString);
Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
2

Change:

public static object doResults()

to:

public static ResultsObj doResults()

then:

string getString = secondObj.resultsString;
Mariusz
  • 442
  • 5
  • 16