我正在为ASP.NET MVC做Nerd Dinner tutorial,我遇到了一个看起来非常奇怪的C#语言结构。这个问题的标题有点模糊,因为我无法定义这是什么。这也使我很难搜索这个主题,因此我决定提出一个问题。
在Nerd Dinner tutorial中,我看到以下代码片段:
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
是当前类的属性,而不是它自己的类。
答案 0 :(得分:10)
这是因为它是extension method。这就是“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中被大量使用。
答案 1 :(得分:3)
这种观察确实是正确的;这是一个扩展方法,如参数类型之前的this
修饰符所示:
this ModelStateDictionary modelState
编译器将解析对查找方法的调用,就像ModelStateDictionary
的实例方法一样,但请注意它仍然实际一个静态调用 - 所以:
obj.SomeStaticMethod(arg1, arg2);
实际编译为:
TheDeclaringType.SomeStaticMethod(obj, arg1, arg2);
可导致obj
之类的奇怪内容,可以是null
,并且调用仍然有效。