Объявление статического метода в одном классе и использование его в качестве метода другого класса - PullRequest
2 голосов
/ 18 ноября 2010

Я делаю учебник Nerd Dinner для ASP.NET MVC, и я встретил одну конструкцию на языке C #, которая казалась очень странной. Название этого вопроса немного расплывчато, потому что мне сложно определить, что это такое. Это также затрудняло мне поиск по теме, поэтому я решил задать вопрос об этом.

В уроке Nerd Dinner Я вижу следующий фрагмент кода:

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);
        }
    }
}

И позже они показывают:

//
// 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);
    }
}

Части, которые меня озадачивают:

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

и

ModelState.AddRuleViolations(dinner.GetRuleViolations());

Похоже, что вы определяете функцию AddRuleViolations в классе ControllerHelpers, а затем вызываете ее, как если бы она была функцией экземпляра свойства ModelState. Это наблюдение правильно? Если да, зачем вам это? Мне кажется очень странным определять метод в одном классе, как если бы он был методом другого класса.

Примечание: ModelState является свойством текущего класса, а не самим классом.

Ответы [ 2 ]

10 голосов
/ 18 ноября 2010

Это потому, что это метод расширения . Это то, что бит «this» находится в начале первого параметра.

Идея методов расширения заключается в том, что они позволяют эффективно добавлять функциональность в существующие классы. Так что если у вас есть:

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

тогда вы можете назвать это так:

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

это на самом деле компилируется, как если бы вы написали:

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

Методы расширения должны быть объявлены в неуниверсальных статических классах верхнего уровня. Они активно используются в LINQ.

3 голосов
/ 18 ноября 2010

Это наблюдение действительно верно; это метод расширения , как отмечено модификатором this перед типом параметра:

this ModelStateDictionary modelState

Компилятор затем разрешает вызовы к методу , выглядящие как метод экземпляра ModelStateDictionary, но имейте в виду, что это все еще на самом деле статический вызов - так:

obj.SomeStaticMethod(arg1, arg2);

это на самом деле скомпилировано как:

TheDeclaringType.SomeStaticMethod(obj, arg1, arg2);

, что может привести к странностям, таким как obj, может быть null , и вызов все равно будет работать .

...