2010-11-18 5 views
2

Ich mache die Nerd Dinner tutorial für ASP.NET MVC und ich traf eine Konstruktion in der Sprache C#, die sehr seltsam schien. Der Titel dieser Frage ist ein wenig vage, weil ich Schwierigkeiten haben, zu definieren, was das ist. Das machte es auch schwierig für mich, über das Thema zu suchen, daher entscheide ich darüber eine Frage zu stellen.Eine statische Methode in einer Klasse deklarieren und als Methode einer anderen Klasse verwenden

Im Nerd Dinner tutorial ich das folgende Codefragment sehen:

public static class ControllerHelpers { 

    public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable<RuleViolation> errors) { 

     foreach (RuleViolation issue in errors) { 
      modelState.AddModelError(issue.PropertyName, issue.ErrorMessage); 
     } 
    } 
} 

Und später zeigen sie:

// 
// GET: /Dinners/Edit/2 

public ActionResult Edit(int id) { 

    Dinner dinner = dinnerRepository.GetDinner(id); 

    return View(dinner); 
} 

// 
// POST: /Dinners/Edit/2 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Edit(int id, FormCollection formValues) { 

    Dinner dinner = dinnerRepository.GetDinner(id); 

    try { 

     UpdateModel(dinner); 

     dinnerRepository.Save(); 

     return RedirectToAction("Details", new { id=dinner.DinnerID }); 
    } 
    catch { 

     ModelState.AddRuleViolations(dinner.GetRuleViolations()); 

     return View(dinner); 
    } 
} 

Die Teile, die mir Rätsel sind:

public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable<RuleViolation> errors) 

und

ModelState.AddRuleViolations(dinner.GetRuleViolations()); 

Es sieht so aus, als ob Sie die AddRuleViolations-Funktion in der ControllerHelpers-Klasse definieren und dann aufrufen, als ob es eine Instanzfunktion der ModelState-Eigenschaft wäre. Ist diese Beobachtung richtig? Wenn ja, warum brauchen Sie das? Es scheint mir sehr seltsam, eine Methode in einer Klasse zu definieren, als ob es sich um eine Methode einer anderen Klasse war.

Hinweis: ModelState ist eine Eigenschaft der aktuellen Klasse und keine Klasse selbst ein.

Antwort

10

Es ist, weil es eine extension method ist. Das ist das Bit "this" am Anfang des ersten Parameters.

Die Idee der Erweiterungsmethoden ist, dass Sie effektiv Funktionalität zu vorhandenen Klassen hinzufügen können. Also, wenn Sie haben:

public static class StringExtensions 
{ 
    public static string Reverse(this string text) 
    { 
     char[] chars = text.ToCharArray(); 
     Array.Reverse(chars); 
     return new string(chars); 
    } 
} 

dann kann man es so nennen:

string x = "hello world"; 
string y = x.Reverse(); 

, die tatsächlich erstellt wird, als ob Sie geschrieben hatte:

string x = "hello world"; 
string y = StringExtensions.Reverse(x); 

Erweiterungsmethoden müssen sein in nicht-generischen statischen Klassen der obersten Ebene deklariert. Sie werden in LINQ häufig verwendet.

+0

Ah danke. Ich konnte vorher nichts ohne das Schlüsselwort extension methods finden. –

3

Diese Beobachtung ist in der Tat richtig; dies ist eine Erweiterungsmethode, wie sie in dem this Modifikator vor dem Parameter-Typ festgestellt:

this ModelStateDictionary modelState 

Der Compiler wird dann Aufrufe an die Methode löst wie eine Instanzmethode von ModelStateDictionary suchen, aber beachten Sie, dass es ist nach wie vor tatsächlich ein statischer Aufruf - so:

obj.SomeStaticMethod(arg1, arg2); 

ist als tatsächlich zusammengestellt:

TheDeclaringType.SomeStaticMethod(obj, arg1, arg2); 

, die in Seltsamkeiten wie obj führen kann nullund der Anruf wird noch arbeiten.

+0

Danke für Ihre Antwort. Also wenn ich 'obj.SomeStaticMethod' aufrufen würde, wobei' obj' 'null' ist und innerhalb der Funktion' obj = new Object() '. Und ist das auch mit Werttypen möglich? –

+0

'Matthijs' Sie können es einen Wert geben * innerhalb der Methode *, aber der Parameter ist nicht' ref' (und kann nicht sein), so wird es ** ** ** ** die Methode * nicht ** zurück * zeigen. 'structs' kann nicht null sein (außer' Nullable '), aber das gleiche gilt: Da es nicht' ref 'ist, wird eine Neuzuweisung nicht außerhalb der Methode angezeigt. –