I am doing the Nerd Dinner tutorial for ASP.NET MVC and I met one construction in the C# language that seemed very strange. The title of this question is a bit vague, because I have trouble defining what this is. This also made it difficult for me to search about the topic, hence I decide to ask a question about it.
In the Nerd Dinner tutorial I see the following code fragment:
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);
}
}
}
And later they show:
//
// 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);
}
}
The parts that puzzle me are:
public static void AddRuleViolations(this ModelStateDictionary modelState, IEnumerable<RuleViolation> errors)
and
ModelState.AddRuleViolations(dinner.GetRuleViolations());
It looks like you define the AddRuleViolations
function in the ControllerHelpers
class and then invoke it as if it was an instance function of the ModelState
property. Is this observation correct? If yes, why would you need this? It looks very strange to me to define a method in one class as if it was a method of another class.
Note: ModelState
is a property of the current class and not a class it self.
It's because it's an extension method. That's what the "this" bit is at the start of the first parameter.
The idea of extension methods is that they allow you to effectively add functionality to existing classes. So if you have:
public static class StringExtensions
{
public static string Reverse(this string text)
{
char[] chars = text.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}
then you can call it like this:
string x = "hello world";
string y = x.Reverse();
that actually gets compiled as if you'd written:
string x = "hello world";
string y = StringExtensions.Reverse(x);
Extension methods have to be declared in top-level non-generic static classes. They're heavily used in LINQ.
That observation is indeed correct; this is an extension method, as noted by the this
modifier before the parameter-type:
this ModelStateDictionary modelState
The compiler will then resolve calls to the method looking like an instance method of ModelStateDictionary
, but note that it is still actually a static call - so:
obj.SomeStaticMethod(arg1, arg2);
is actually compiled as:
TheDeclaringType.SomeStaticMethod(obj, arg1, arg2);
which can result in oddities such as obj
can be null
and the call will still work.
精彩评论