Perché devo usare "this" per chiamare un metodo di estensione all'interno della classe estesa?

StackOverflow https://stackoverflow.com/questions/1616294

  •  06-07-2019
  •  | 
  •  

Domanda

Ho scritto dozzine di metodi di estensione e funzionano tutti come previsto. Ma questa è la prima volta che ho incontrato un metodo di estensione in questo contesto.

public static class ControllerExtensions
{
    public static RedirectToRouteResult RedirectToAction<TController>(
        this Controller controller
        , Expression<Action<TController>> action
      ) where TController : Controller
    {
      RouteValueDictionary routeValuesFromExpression = 
        ExpressionHelper.GetRouteValuesFromExpression<TController>(action);

      return new RedirectToRouteResult(routeValuesFromExpression);
    }
}

Sembra abbastanza normale, giusto? Ma nei miei controller, non riesco ad accedere a questo metodo di estensione digitando. Devo invece aggiungere il prefisso con la parola chiave "this". Ad esempio:

// This does not work, I get a compiler error because
// RedirectToAction has no overload for the generic.
//
return
  RedirectToAction<MembershipController>(
     c => c.RegisterSuccess(Server.UrlEncode(code) ));

// But, this does work?!?!
//
return
  this.RedirectToAction<MembershipController>(
     c => c.RegisterSuccess(Server.UrlEncode(code) ));

Molto strano. Forse è perché mi trovo nell'oggetto istanza che sto estendendo? Il "controller" istanza che è?

Certo, sono stato in grado di duplicarlo in una semplice app console:

class Program
{
    static void Main(string[] args)
    {
        var x = new TestClass();
        x.Go<String>();
    }
}

public class TestClass
{
    public void Go()
    {
    }

    public void NextMethod()
    {
        // compiler error.  :(
        Go<String>();

        // works!
        this.Go<String>();
    }
}

public static class TestExtension
{
    public static string Go<T>(this TestClass theClass)
    {
        return String.Empty;
    }
}

Quindi perché 'questo'. lavorare?

È stato utile?

Soluzione

I metodi di estensione non fanno parte di " default " ricerca membri - devi utilizzare un'espressione del modulo Target.Method prima di controllare i metodi di estensione. this.Foo () è conforme a tale requisito, quindi funziona.

Dalla sezione 7.5.5.2:

  

In una chiamata di metodo (§7.5.5.1) di   una delle forme

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args ) if the normal processing of the
     

l'invocazione non trova applicabile   metodi, viene effettuato un tentativo di elaborazione   il costrutto come metodo di estensione   invocazione.

Certamente tutto ciò che dice è "il compilatore sta seguendo le specifiche" piuttosto che il motivo per cui la specifica è stata scritta in quel modo ... Non so se sia un motivo specifico, sebbene il fatto che tu possa invocare entrambi i membri dell'istanza e i membri statici che usano solo Metodo () (invece di specificare un'istanza o un tipo) possono essere rilevanti.

Altri suggerimenti

Penso che sia a causa di come funzionano i metodi di estensione.

Quando scrivi Go (), il compilatore presuppone che Go sia un metodo nella classe corrente, che non lo è.

I metodi di estensione sono "collegati" a un'istanza e si specifica l'istanza utilizzando questa parola chiave.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top