none
Is it possible to get the "this" reference from the generic argument type? RRS feed

  • Question

  • Dear All,

    I would like to extract the method to base class or base method(that is for all WinForms multilingual text load), and generic parameter T type is used in this method to do multilingual text load,

    like below, snippet 1 and snippet 2, my question is

    is it possible to get the "this" reference from the generic argument T?

    Or the only way is to change the method to snippet 3? (I have tested it, it is OK)

    Thanks and Best regards,

    E-John

                TYMultilinguist linguist = TYMultilinguist.GetInstance();
                string neutralCulture = linguist.GetAppUISavedNeutralCulture();
                MultiLangChangeContrlTextLanguage(neutralCulture, this);

    snippet 1

            private void MultiLangChangeControlTextRecursive(ComponentResourceManager resources, CultureInfo cult, Control control)
            {
                if (control.Controls.Count != 0)
                {
                    foreach (Control ctrl in control.Controls)
                    {
                        resources.ApplyResources(ctrl, ctrl.Name, cult);

                        MultiLangChangeControlTextRecursive(resources, cult, ctrl);
                    }
                }
            }

    private void MultiLangChangeContrlTextLanguage<T>(string neutralCulture, T type) { ComponentResourceManager resources = new ComponentResourceManager(typeof(T)); CultureInfo cult = new CultureInfo(neutralCulture); // change Win Form title

    // Is it possible to get "this" from type??? resources.ApplyResources(this, "$this", cult); // Buttons are embedded in the GroupBox // e.g., this.Controls.Add(this.groupBoxPassword); // and this.groupBoxPassword.Controls.Add(this.maskedTextBoxPassword); foreach (Control ctrl in this.Controls) { resources.ApplyResources(ctrl, ctrl.Name, cult); MultiLangChangeControlTextRecursive(resources, cult, ctrl); } }

    snippet 2

    private void MultiLangChangeContrlTextLanguage(string neutralCulture, Form form)
    {
        ComponentResourceManager resources = new ComponentResourceManager(form.GetType());
        CultureInfo cult = new CultureInfo(neutralCulture);
    
        // change Win Form title
        resources.ApplyResources(form, "$this", cult);
    
        foreach (Control ctrl in form.Controls)
        {
            resources.ApplyResources(ctrl, ctrl.Name, cult);
    
            MultiLangChangeControlTextRecursive(resources, cult, ctrl);
        }
    }

    snippet 3



    • Edited by E-John Thursday, January 3, 2019 2:20 PM
    Thursday, January 3, 2019 2:17 PM

Answers

  • Generics and this are completely unrelated so I'm going to say no just on the premise. A generic is simply replacing a parameter's type with a more generic (unspecified) type until it is used. So you don't have any more or less access to the value then you would before, just the type is changing.

    'this' only works inside instance methods and always apply to the current instance it is run against. Therefore you cannot use 'this' outside that context. Generics don't make any sense here because you always know the type (it is the current type or a derived instance). Irrelevant 'this' is 'this'.

    "is it possible to get the "this" reference from the generic argument T?"

    This question makes no sense to me so let's approach it from a design point of view. Generic methods are nothing more than normal methods except the compiler "creates" the method based upon how it is called. Logically this is how it works. In reality the compiler will auto-create a new method for each value type that is used but all reference types will actually use a single "object" version with the compiler magic fixing up the type. So when you define a method like this.

    void Foo<T> ( T value )
    {
    }

    And then use it like this.

    Foo(10);
    Foo(true);
    Foo(myProgram);

    Then the compiler (logically) generates the following methods as though you wrote them. Again note that for ref types it actually only creates a single implementation that works for all reference types.

    void Foo ( int value ) {}
    void Foo ( bool value ) {}
    void Foo ( Program value ) { }

    So given the above methods, there is nothing you can do with 'this' that is related to these parameters. 'this' in Foo would be referring to the type defining Foo, not the parameters. If you wanted to access "the instance" of the parameter you'd just use the parameter name.

    Remember that 'this' is just compiler sugar to differentiate the current instance's members from any locals/parameters you may be referring to in code. It is strictly to disambiguate the current instance members from everybody else. The following code is all the same.

    class MyType
    {
       public MyType CurrentInstance = this;
    
       public void Foo ()
       {
          var areEqual = _field == this._field;
       }
       int _field;
    }
    
    var instance = new MyType();
    
    var areEqual = instance == instance.CurrentInstance;
    
    

    Now let's look at your code. In snippet 2 you want 'type' to be generic. When called you'll be passed an instance of 'type'. That is the 'this' for that instance. So you would just reference the parameter 'type' in places where you want the "instance" of the type. The 'type' argument is the same value as the 'this' keyword inside the instance (you were passed) of T.

    In snippet 2 you're using 'this' to enumerate the controls. That means that the method is inside a type deriving from Form otherwise it won't compile. In snippet 3 you are using Form instead. In snippet 2 if T were of type Form then you'd have the equivalent logic. But 'this' (for T) wouldn't be accessible because 'this' is always the current instance. You could however define T with a constraint of Form. Then you could access the (already public) Controls property. None of this has anything to do with 'this' though.

    private void MultiLangChangeContrlTextLanguage<T> (string neutralCulture, T form) where T: Form
    {
        ComponentResourceManager resources = new ComponentResourceManager(form.GetType());
        CultureInfo cult = new CultureInfo(neutralCulture);
    
        // change Win Form title
        resources.ApplyResources(form, "$this", cult);
    
        foreach (Control ctrl in form.Controls)
        {
            resources.ApplyResources(ctrl, ctrl.Name, cult);
    
            MultiLangChangeControlTextRecursive(resources, cult, ctrl);
        }
    }


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by E-John Friday, January 4, 2019 2:48 AM
    Thursday, January 3, 2019 4:00 PM
    Moderator

All replies

  • Generics and this are completely unrelated so I'm going to say no just on the premise. A generic is simply replacing a parameter's type with a more generic (unspecified) type until it is used. So you don't have any more or less access to the value then you would before, just the type is changing.

    'this' only works inside instance methods and always apply to the current instance it is run against. Therefore you cannot use 'this' outside that context. Generics don't make any sense here because you always know the type (it is the current type or a derived instance). Irrelevant 'this' is 'this'.

    "is it possible to get the "this" reference from the generic argument T?"

    This question makes no sense to me so let's approach it from a design point of view. Generic methods are nothing more than normal methods except the compiler "creates" the method based upon how it is called. Logically this is how it works. In reality the compiler will auto-create a new method for each value type that is used but all reference types will actually use a single "object" version with the compiler magic fixing up the type. So when you define a method like this.

    void Foo<T> ( T value )
    {
    }

    And then use it like this.

    Foo(10);
    Foo(true);
    Foo(myProgram);

    Then the compiler (logically) generates the following methods as though you wrote them. Again note that for ref types it actually only creates a single implementation that works for all reference types.

    void Foo ( int value ) {}
    void Foo ( bool value ) {}
    void Foo ( Program value ) { }

    So given the above methods, there is nothing you can do with 'this' that is related to these parameters. 'this' in Foo would be referring to the type defining Foo, not the parameters. If you wanted to access "the instance" of the parameter you'd just use the parameter name.

    Remember that 'this' is just compiler sugar to differentiate the current instance's members from any locals/parameters you may be referring to in code. It is strictly to disambiguate the current instance members from everybody else. The following code is all the same.

    class MyType
    {
       public MyType CurrentInstance = this;
    
       public void Foo ()
       {
          var areEqual = _field == this._field;
       }
       int _field;
    }
    
    var instance = new MyType();
    
    var areEqual = instance == instance.CurrentInstance;
    
    

    Now let's look at your code. In snippet 2 you want 'type' to be generic. When called you'll be passed an instance of 'type'. That is the 'this' for that instance. So you would just reference the parameter 'type' in places where you want the "instance" of the type. The 'type' argument is the same value as the 'this' keyword inside the instance (you were passed) of T.

    In snippet 2 you're using 'this' to enumerate the controls. That means that the method is inside a type deriving from Form otherwise it won't compile. In snippet 3 you are using Form instead. In snippet 2 if T were of type Form then you'd have the equivalent logic. But 'this' (for T) wouldn't be accessible because 'this' is always the current instance. You could however define T with a constraint of Form. Then you could access the (already public) Controls property. None of this has anything to do with 'this' though.

    private void MultiLangChangeContrlTextLanguage<T> (string neutralCulture, T form) where T: Form
    {
        ComponentResourceManager resources = new ComponentResourceManager(form.GetType());
        CultureInfo cult = new CultureInfo(neutralCulture);
    
        // change Win Form title
        resources.ApplyResources(form, "$this", cult);
    
        foreach (Control ctrl in form.Controls)
        {
            resources.ApplyResources(ctrl, ctrl.Name, cult);
    
            MultiLangChangeControlTextRecursive(resources, cult, ctrl);
        }
    }


    Michael Taylor http://www.michaeltaylorp3.net

    • Marked as answer by E-John Friday, January 4, 2019 2:48 AM
    Thursday, January 3, 2019 4:00 PM
    Moderator
  • Maybe like this:

    private void MultiLangChangeContrlTextLanguage ( string neutralCulture, Control parentControl)

    {

       ComponentResourceManager resources = new ComponentResourceManager(parentControl.GetType());

       . . .

       resources.ApplyResources( parentControl, "$this", cult);

       foreach (Control ctrl in parentControl.Controls)

       . . .

    }

    It can be called for forms too; (last parameter can be a form).


    • Edited by Viorel_MVP Thursday, January 3, 2019 4:20 PM
    Thursday, January 3, 2019 4:16 PM
  • Dear CoolDadTx,

    Got it. Thanks for your great helps and detailed explanations.

    'this' only works inside instance methods and always apply to the current instance it is run against. Therefore you cannot use 'this' outside that context

    In snippet 2 you're using 'this' to enumerate the controls. That means that the method is inside a type deriving from Form otherwise it won't compile. In snippet 3 you are using Form instead. In snippet 2 if T were of type Form then you'd have the equivalent logic. But 'this' (for T) wouldn't be accessible because 'this' is always the current instance. You could however define T with a constraint of Form. Then you could access the (already public) Controls property. None of this has anything to do with 'this' though.

    -> Yes. In snippet 2, 'this' works because the method is within the class FormSub, and 'this' is refer to the class FormSub's instance itself. This part was not described in previous post.

    Like below shows,

        public partial class FormSub : Form
        {

    private void MultiLangChangeContrlTextLanguage<T>(string neutralCulture, T type)

    {
    ...

    }              ...

        }


    Friday, January 4, 2019 2:47 AM