Don't get the use of the "this" keyword in this instance

  • (2 Pages)
  • +
  • 1
  • 2

17 Replies - 789 Views - Last Post: 03 February 2020 - 03:48 PM Rate Topic: -----

#16 h4nnib4l   User is offline

  • The Noid
  • member icon

Reputation: 1500
  • View blog
  • Posts: 2,101
  • Joined: 24-August 11

Re: Don't get the use of the "this" keyword in this instance

Posted 03 February 2020 - 10:03 AM

Maybe an actual use-case for the functionality would help...

Borrowing from xclite's example with some tweaks, let's imagine a public Thing class in your class library - which is intended to be exposed to anything that references the assembly - and an internal ThingHelper class that encapsulates some work that the Thing class can do, but isn't exposed outside of the assembly.

public class Thing
{
    public Thing(int value)
    {
        Value = value;
    }

    public int Value { get; private set; }

    public int ApplyMagicProcessingToValue(int magicValue)
    {
        var helper = new ThingHelper(this);
        return helper.DoTheMagic(magicValue);
    }
}

internal class ThingHelper
{
    public ThingHelper(Thing thing)
    {
        MyThing = thing;
    }

    private Thing MyThing { get; set; }

    public int DoTheMagic(int value)
    {
        return MyThing.Value + value;
    }
}



We want the Thing class to have the ability to do some magic processing against its public Value property based on a supplied magicValue argument, but we don't want to expose the internal workings of the magic. So in the ApplyMagicProcessingToValue method, the Thing instance is actually going to spin up an instance of the ThingHelper class, passing a reference to itself, and use that ThingHelper instance to DoTheMagic(). ThingHelper needs a reference to the Thing instance it's helping so that it can use its Value in the calculation.

I know it's a silly example, because in this case it would be easier to just give Thing the ability to do that work, but if we take it a step further, we could say that ThingHelper is actually a 3rd party assembly that we don't have access to - even we don't know what DoTheMagic does, so we can't just give Thing the ability to do it. Or maybe it's an assembly controlled by another team and used in multiple applications - in this case, we don't really care what it does, we just need all apps to get the same answer when they use it.

Hopefully that helps, rather than convolutes.
Was This Post Helpful? 0
  • +
  • -

#17 valkenberg   User is offline

  • D.I.C Head

Reputation: 1
  • View blog
  • Posts: 65
  • Joined: 22-February 17

Re: Don't get the use of the "this" keyword in this instance

Posted 03 February 2020 - 01:59 PM

Ok, so going back to the high level stuff, a lot fell into place when I actually ran the program.

namespace ThisKeywordDemo
{
    using System;
    public class Foo
    {
        public Foo(object item)
        {
            Console.WriteLine(item);
            Console.ReadLine();
        }
    }

    public class Program
    {
        public void bar()
        {
            var foo = new Foo(this);
        }

        public static void Main()
        {
            var p = new Program();
            p.bar();
        }
    }
}

using System;
namespace
public class Foo
{
	public Foo(object item);
	{
		Console.WriteLine(item);
	}
}

public class Program
{
	public void bar();
	{
		var foo = new Foo(this);
	}
		
public static void Main();
	{
		var p = new Program();
		p.bar();
	}
}



Output:
ThisKeywordDemo.Program

So it looks like the location of foo within the application was passed to Foo's constructor. However, this is not the end of the story. I looked at the example as per the link of astoneciper:

"https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this"

namespace this_Keyword_4_Solution_Employee
{
    class Employee
    {
        private string name;
        private string alias;
        private decimal salary = 6000.00m;

        // Constructor:
        public Employee(string name, string alias)
        {
            // Use this to qualify the fields, name and alias:
            this.name = name;
            this.alias = alias;
        }

        // Printing method:
        public void printEmployee()
        {
            Console.WriteLine("Name: {0}\nAlias: {1}", name, alias);
            // Passing the object to the CalcTax method by using this:
            Console.WriteLine("Taxes: {0:C}", Tax.CalcTax(this));
            Console.ReadLine();
        }

        public decimal Salary
        {
            get { return salary; }
        }
    }

    class Tax
    {
        public static decimal CalcTax(Employee E)
        {
            return 0.08m * E.Salary;
        }
    }

    class MainClass
    {
        static void Main()
        {
            // Create objects:
            Employee E1 = new Employee("Mingda Pan", "mpan");

            // Display results:
            E1.printEmployee();
        }
    }
}


Output:
Name: Mingda Pan
Alias: mpan
Taxes: $480.00

In summary:

Foo example:
public Foo(object item)
var foo = new Foo(this);
 


Employee example:
public static decimal CalcTax(Employee E)
Tax.CalcTax(this)



If "this" passes a reference then is it telling CalcTax, the reference to the object you need is this_Keyword_4_Solution_Employee.Employee? CalcTax then goes to this reference and so gets E1?

Or does Tax.CalcTax(this) pass E1 directly to CalcTax?

So does "this" always pass a reference irrespective of the parameter list of the calling function?

With Foo had (object item) and with Employee have (Employee E).

h4nnib4l - thanks. Will study your post now.
Was This Post Helpful? 0
  • +
  • -

#18 h4nnib4l   User is offline

  • The Noid
  • member icon

Reputation: 1500
  • View blog
  • Posts: 2,101
  • Joined: 24-August 11

Re: Don't get the use of the "this" keyword in this instance

Posted 03 February 2020 - 03:48 PM

View Postvalkenberg, on 03 February 2020 - 02:59 PM, said:

Output:
ThisKeywordDemo.Program

So it looks like the location of foo within the application was passed to Foo's constructor.


Not quite, and I think I see what's confusing you now. Calling Console.WriteLine directly on a class will output the full name of the class, i.e. namespace.classname. It's not the location per se, it's just the string representation of the class, which is going to be the name if the class doesn't specify different behavior for the ToString() method via an override (don't worry about ToString() overrides if that sentence doesn't make sense to you).

Try this: modify your ThisKeywordDemo like this and run it.

namespace ThisKeywordDemo
{
    using System;
    public class Foo
    {
        public Foo(Program item)
        {
            Console.WriteLine(item.MyString);
                
        }
    }

    public class Program
    {
        public void bar()
        {
            var foo = new Foo(this);
        }

        public string MyString { get; set; }

        public static void Main()
        {
            var p = new Program();
            p.MyString = "Hello from Program instance 'p'.";
            p.bar();

            var q = new Program();
            q.MyString = "Hello from Program instance 'q'.";
            q.bar();

            Console.ReadKey();
        }
    }
}



What's getting passed to the new instance of Foo that is instantiated in Bar is the instance of Program that you're creating in Main(). If you run the new version of the code, you'll see that the constructor of Foo is writing the value of MyString from whatever instance it receives as an argument. Try putting a break point on the first line (var p = new Program();) and stepping through. Use F11 so that you drop into the called methods. Watch the flow, and open up item each time you drop into Foo's constructor so that you can see the value of MyString.

Try this next: take my original example and run it from a console app.

public class Thing
{
    public Thing(int value)
    {
        Value = value;
    }

    public int Value { get; private set; }

    public int ApplyMagicProcessingToValue(int magicValue)
    {
        var helper = new ThingHelper(this);
        return helper.DoTheMagic(magicValue);
    }
}

internal class ThingHelper
{
    public ThingHelper(Thing thing)
    {
        MyThing = thing;
    }

    private Thing MyThing { get; set; }

    public int DoTheMagic(int value)
    {
        return MyThing.Value + value;
    }
}

class Program
{

    public static void Main(string[] args)
    {
        var originalValue = 7;
        var magicValue = 3;

        var thing = new Thing(originalValue);
        var newValue = thing.ApplyMagicProcessingToValue(magicValue);

        Console.WriteLine($"Original value: {originalValue}");
        Console.WriteLine($"Magic value: {magicValue}");
        Console.WriteLine($"New value: {newValue}");

        Console.ReadKey();
    }

}



Do the same thing: put a break point on the first line, and step through the execution. Watch as you drop into the different constructors and method calls, break open instances of Thing and ThingHelper as they're created, notice when they fall out of scope and go away, and finally check out the output so that you can see the result of the operation.

This post has been edited by h4nnib4l: 03 February 2020 - 03:51 PM

Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2