知乎周源微信
And so, Dear Reader, I present to you twenty-first in a infinite number of posts of "The Weekly Source Code." I'm doubling up this week, but the ASP.NET MVC Source was released today and I wanted to share more thoughts. I would also encourage you to check out TWSC 17 on Community ASP.NET MVC code.
因此,尊敬的读者,我在“每周源代码”的无数帖子中向您介绍了第二十一。 我本周要加倍,但是ASP.NET MVC Source已于今天发布,我想分享更多想法。 我也鼓励您在社区ASP.NET MVC代码上查看TWSC 17 。
阅读评论 (Read the Comments)
When you're reading source, look for words like "TODO," "HACK," "REVIEW," etc, to find parts of the code that the writers are concerned about.
当您阅读源代码时,查找诸如“ TODO”,“ HACK”,“ REVIEW”等之类的单词,以查找编写者所关注的代码部分。
In the SelectBuilder.cs, there's a comment that says:
在SelectBuilder.cs中,有一条注释:
// TODO: Should these be HTML encoded or HTML attribute encoded? Need to review all helper methods that call this.
string thisText = HttpUtility.HtmlEncode(listData[key].ToString());
string thisValue = HttpUtility.HtmlEncode(key.ToString());
This is an interesting question. He's asking if they should use System.Web.HttpUtility.HtmlAttributeEncode or HtmlEncode. HTML Attribute Encoding encodes <, " and &.
这是个有趣的问题。 他在问他们是否应该使用System.Web.HttpUtility.HtmlAttributeEncode或HtmlEncode。 HTML属性编码对<,“和&进行编码。
In ViewUserControl.cs we see these:
在ViewUserControl.cs中,我们看到以下内容:
public virtual void RenderView(ViewContext viewContext) {
// TODO: Remove this hack. Without it, the browser appears to always load cached output
viewContext.HttpContext.Response.Cache.SetExpires(DateTime.Now);
ViewUserControlContainerPage containerPage = new ViewUserControlContainerPage(this);
containerPage.RenderView(viewContext);
}
This is a tough one also. Chasing caching issues is a huge hassle and consumed at least 10% of my time when I was writing banking software. Even now it feels like there are subtle (and not-so-subtle) differences between IE and Firefox. Seems like Firefox really caches aggressively.
这也是一项艰巨的任务。 追逐缓存问题非常麻烦,在编写银行软件时,至少消耗了我10%的时间。 即使到现在,感觉就像IE和Firefox之间仍然存在细微(但不是那么细微)的差异。 好像Firefox确实积极地缓存。
There's a few marked "REVIEW" like:
有一些标记为“ REVIEW”的内容,例如:
// REVIEW: Should we make this public?
internal interface IBuildManager {
object CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType);
ICollection GetReferencedAssemblies();
}
And this one, which is kind of funny. The property IsReusable in an HttpHandler indicates whether or not an instance has state and as such, should not be reused by ASP.NET property. If you write an HttpHandler and it has no state, just a ProcessRequest, you can "reuse" it which should result in a small perf gain.
这个很有趣。 HttpHandler中的IsReusable属性指示实例是否具有状态,因此不应被ASP.NET属性重用。 如果您编写一个HttpHandler且没有状态,而只是一个ProcessRequest,则可以“重用”它,这会带来很小的性能提升。
protected virtual bool IsReusable {
get {
// REVIEW: What's this?
return false;
}
}
Here's one about overloads:
这是关于重载的一个:
//REVIEW: Should we have an overload that takes Uri?
[SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings",
Justification = "As the return value will used only for rendering, string return value is more appropriate.")]
[SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
Justification = "Needs to take same parameters as HttpUtility.UrlEncode()")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
Justification = "For consistency, all helpers are instance methods.")]
public string Encode(string url) {
return HttpUtility.UrlEncode(url);
}
We've all written comments like these. The trick is to make sure you've included all your key words in Visual Studio so that all your comments will show up in the Task List and can be dealt with before you ship.
我们都写过这样的评论。 诀窍是确保在Visual Studio中包含所有关键字,以便所有注释都将显示在“任务列表”中,并可以在发货前进行处理。
查看SuppressMessage (Check out SuppressMessage)
Microsoft uses CodeAnalysis a lot and you should too. However, sometimes CodeAnalysis offers suggestions that are wrong or not really appropriate and you'll want to suppress those.
微软经常使用CodeAnalysis,您也应该这样做。 但是,有时CodeAnalysis提供的建议是错误的或不真正合适的,您将希望予以抑制。
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate",
Justification = "There is already a ViewData property and it has a slightly different meaning.")]
protected internal virtual void SetViewData(object viewData) {
_viewData = viewData;
}
Looking for references to SuppressMessage is a good way to find out where unwavering "purity" analytics fall down and pragmatism should win the day. That said, it never hurts to reevaluate these occasionally as opportunities for refactoring.
寻找对SuppressMessage的引用是找出毫不动摇的“纯度”分析在何处下降以及实用主义应运而生的好方法。 话虽如此,偶尔将它们重新评估为重构机会也没有什么害处。
The most interesting aspect is the Justification attribute which is actual prose written by the developers. For example, this is the contents of GlobalSuppressions.cs:
最有趣的方面是Justification属性,它是开发人员编写的实际散文。 例如,这是GlobalSuppressions.cs的内容:
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "System.Web.Mvc.TempDataDictionary.#System.Collections.Generic.ICollection`1<system.collections.generic.keyvaluepair `2>)",
Justification = "There are no defined scenarios for wanting to derive from this class, but we don't want to prevent it either.")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "System.Web.Mvc.TempDataDictionary.#System.Collections.Generic.ICollection`1<system.collections.generic.keyvaluepair `2>[],System.Int32)",
Justification = "There are no defined scenarios for wanting to derive from this class, but we don't want to prevent it either.")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes", Scope = "member", Target = "System.Web.Mvc.TempDataDictionary.#System.Collections.Generic.ICollection`1<system.collections.generic.keyvaluepair `2>
>.IsReadOnly",
Justification = "There are no defined scenarios for wanting to derive from this class, but we don't want to prevent it either.")]
Here's a good example of a justification:
这是一个合理的例子:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "The return value is not a regular URL since it may contain ~/ ASP.NET-specific characters")]
public static string SubmitImage(this HtmlHelper helper, string htmlName, string imageRelativeUrl) {
return SubmitImage(helper, htmlName, imageRelativeUrl, null);
}
Code analysis is warning that there's a string parameter with the name "Url", but the justification is valid: "The value is not a regular URL since it may contain ~/ ASP.NET-specific characters"
代码分析警告说,有一个名为“ Url”的字符串参数,但是这种说法是合法的: “该值不是常规URL,因为它可能包含〜/ ASP.NET特定字符”
期待实用程序 (Look to Utils)
As I've said before, whenever I start reading code, I look for things marked "Util." These tell us a few things. Things named Util show the "underbelly" of code and point out where things could either be better factored, either in the thing your reading, or in the larger Framework whatever your reading lives in.
就像我之前说过的,每当我开始阅读代码时,我都会寻找标记为“ Util”的东西。 这些告诉我们一些事情。 名为Util的事物显示了代码的“不足之处”,并指出了可以更好地分解因素的地方,无论是您所阅读的内容,还是更大范围内的框架,无论您所阅读的内容如何。
In ASP.NET MVC's project there's a Util folder and a Pair.cs file, so let's check it out.
在ASP.NET MVC的项目中,有一个Util文件夹和Pair.cs文件,因此让我们检查一下。
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
namespace System.Web.Util {
using System;
// Generic Pair class. Overrides Equals() and GetHashCode(), so it can be used as a dictionary key.
internal sealed class Pair
{
private readonly TFirst _first;
private readonly TSecond _second;
public Pair(TFirst first, TSecond second) {
_first = first;
_second = second;
}
public TFirst First {
get {
return _first;
}
}
public TSecond Second {
get {
return _second;
}
}
public override bool Equals(object obj) {
if (obj == this) {
return true;
}
Pair
other = obj as Pair
;
return (other != null) &&
(((other._first == null) && (_first == null)) ||
((other._first != null) && other._first.Equals(_first))) &&
(((other._second == null) && (_second == null)) ||
((other._second != null) && other._second.Equals(_second)));
}
public override int GetHashCode() {
int a = (_first == null) ? 0 : _first.GetHashCode();
int b = (_second == null) ? 0 : _second.GetHashCode();
return CombineHashCodes(a, b);
}
// Copied from ndp\fx\src\xsp\System\Web\Util\HashCodeCombiner.cs
private static int CombineHashCodes(int h1, int h2) {
return ((h1 << 5) + h1) ^ h2;
}
}
}
This is a simple but clever class that uses generics to make a Pair of any two types. The interesting part is the CombineHashCodes method that takes the hash codes from each object and combines them in a way that makes that pair's hashcode unique enough for use in a Hashtable later.
这是一个简单但很聪明的类,它使用泛型将任何两种类型的对配对。 有趣的部分是CombineHashCodes方法,该方法从每个对象中获取哈希码,并将它们组合在一起,从而使该对的哈希码具有足够的唯一性,以便稍后在Hashtable中使用。
The Pair class is used to create a combined object inside the TempDataDictionary class like this:
Pair类用于在TempDataDictionary类内部创建一个组合对象,如下所示:
private Pair<Dictionary<string , object>, HashSet<string>> _sessionData;
...where the Key is the actual TempData storage dictionary, and the value is the list of keys that were modified during one request so that they might survive to the next.
...其中Key是实际的TempData存储字典,而值是在一个请求期间修改的键列表,以便它们可以保留到下一个。
There's lot more to learn from reading this code, and it's going to be fun to watch it grow, change and improve!
阅读此代码还有很多要学习的内容,看到它的增长,更改和改进会很有趣!
翻译自: https://www.hanselman.com/blog/the-weekly-source-code-21-aspnet-mvc-preview-2-source-code
知乎周源微信