好的,我是一名业余程序员,只是写了这篇文章。它完成了工作,但我想知道它有多糟糕,可以做出哪些改进。
[请注意,这是Graffiti CMS的Chalk扩展程序。]
public string PostsAsSlides(PostCollection posts, int PostsPerSlide)
{
StringBuilder sb = new StringBuilder();
decimal slides = Math.Round((decimal)posts.Count / (decimal)PostsPerSlide, 3);
int NumberOfSlides = Convert.ToInt32(Math.Ceiling(slides));
for (int i = 0; i < NumberOfSlides; i++ )
{
int PostCount = 0;
sb.Append("<div class=\"slide\">\n");
foreach (Post post in posts.Skip<Post>(i * PostsPerSlide))
{
PostCount += 1;
string CssClass = "slide-block";
if (PostCount == 1)
CssClass += " first";
else if (PostCount == PostsPerSlide)
CssClass += " last";
sb.Append(string.Format("<div class=\"{0}\">\n", CssClass));
sb.Append(string.Format("<a href=\"{0}\" rel=\"prettyPhoto[gallery]\" title=\"{1}\"><img src=\"{2}\" alt=\"{3}\" /></a>\n", post.Custom("Large Image"), post.MetaDescription, post.ImageUrl, post.Title));
sb.Append(string.Format("<a class=\"button-launch-website\" href=\"{0}\" target=\"_blank\">Launch Website</a>\n", post.Custom("Website Url")));
sb.Append("</div><!--.slide-block-->\n");
if (PostCount == PostsPerSlide)
break;
}
sb.Append("</div><!--.slide-->\n");
}
return sb.ToString();
}
答案 0 :(得分:12)
使用HtmlTextWriter 代替StringBuilder编写HTML:
StringBuilder sb = new StringBuilder();
using(HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(sb)))
{
writer.WriteBeginTag("div");
writer.WriteAttribute("class", "slide");
//...
}
return sb.ToString();
我们不想使用非结构化编写器来编写结构化数据。
将内循环的主体分解为单独的例程:
foreach(...)
{
WritePost(post, writer);
}
//snip
private void WritePost(Post post, HtmlTextWriter writer)
{
//write single post
}
这使得它可以测试并且更容易修改。
使用数据结构管理CSS类等内容。
不要使用空格附加额外的类名,并希望所有内容都在最后排成一行,而是根据需要添加和删除List<string>
个类名,然后调用:
List<string> cssClasses = new List<string>();
//snip
string.Join(" ", cssClasses.ToArray());
答案 1 :(得分:5)
这不是很好,但我看到的情况要糟糕得多。
假设这是ASP.Net,您是否有理由使用此方法而不是转发器?
编辑:
如果在这种情况下无法使用转发器,我建议使用.Net HTML类来生成HTML而不是使用文本。稍后阅读/调整会更容易一些。
答案 2 :(得分:5)
而不是这个,
foreach (Post post in posts.Skip<Post>(i * PostsPerSlide))
{
// ...
if (PostCount == PostsPerSlide)
break;
}
我会将退出条件移动到循环中,如下所示:(并在您使用时消除不必要的通用参数)
foreach (Post post in posts.Skip(i * PostsPerSlide).Take(PostsPerSlide))
{
// ...
}
事实上,你的两个嵌套循环可能只能在一个循环中处理。
另外,我更喜欢使用html属性的单引号,因为这些是合法的,不需要转义。
答案 3 :(得分:2)
我看到的情况要糟糕得多,但你可以改善它。
答案 4 :(得分:2)
我的第一个想法是,单位测试将非常困难。
我建议将第二个for循环作为一个单独的函数,所以你会有类似的东西:
for (int i = 0; i < NumberOfSlides; i++ )
{
int PostCount = 0;
sb.Append("<div class=\"slide\">\n");
LoopPosts(posts, i);
...
和LoopPosts:
private void LoopPosts(PostCollection posts, int i) {
...
}
如果你习惯做这样的循环,那么当你需要进行单元测试时,将更容易测试与外循环分开的内循环。
答案 5 :(得分:1)
我说它看起来不错,代码没有严重问题,而且效果很好。但这并不意味着它无法改进。 :)
以下是一些提示:
对于一般浮点运算,您应该使用double
而不是Decimal
。但是,在这种情况下,您根本不需要任何浮点运算,只需使用整数:
int numberOfSlides = (posts.Count + PostsPerSlide - 1) / PostsPerSlide;
但是,如果您只是在循环中使用单个循环而不是循环中的循环,则根本不需要幻灯片计数。
局部变量的约定是camel case(postCoint)而不是pascal case(PostCount)。尝试使变量名称意义重大,而不是像“sb”那样模糊的缩写。如果变量的范围太小而你真的不需要一个有意义的名称,那么只需要尽可能简单,只需要一个字母而不是缩写。
您可以直接指定文字字符串,而不是连接字符串“slide block”和“first”。这样就可以用简单的赋值替换对String.Concat的调用。 (这与过早优化有关,但另一方面,字符串连接需要大约50倍。)
您可以在StringBuilder上使用.AppendFormat(...)
代替.Append(String.Format(...))
。在这种情况下我会坚持使用Append,因为实际上没有什么需要格式化,你只是连接字符串。
所以,我会写这样的方法:
public string PostsAsSlides(PostCollection posts, int postsPerSlide) {
StringBuilder builder = new StringBuilder();
int postCount = 0;
foreach (Post post in posts) {
postCount++;
string cssClass;
if (postCount == 1) {
builder.Append("<div class=\"slide\">\n");
cssClass = "slide-block first";
} else if (postCount == postsPerSlide) {
cssClass = "slide-block last";
postCount = 0;
} else {
cssClass = "slide-block";
}
builder.Append("<div class=\"").Append(cssClass).Append("\">\n")
.Append("<a href=\"").Append(post.Custom("Large Image"))
.Append("\" rel=\"prettyPhoto[gallery]\" title=\"")
.Append(post.MetaDescription).Append("\"><img src=\"")
.Append(post.ImageUrl).Append("\" alt=\"").Append(post.Title)
.Append("\" /></a>\n")
.Append("<a class=\"button-launch-website\" href=\"")
.Append(post.Custom("Website Url"))
.Append("\" target=\"_blank\">Launch Website</a>\n")
.Append("</div><!--.slide-block-->\n");
if (postCount == 0) {
builder.Append("</div><!--.slide-->\n");
}
}
return builder.ToString();
}
答案 6 :(得分:0)
如果帖子的定义存在会有所帮助,但总的来说,我会说在代码中生成HTML并不是Asp.Net的方法。
因为它被标记为.Net特别......
要显示集合中的项目列表,最好查看其中一个数据控件(转发器,数据列表等)并学习如何正确使用它们。
http://quickstarts.asp.net/QuickStartv20/aspnet/doc/ctrlref/data/default.aspx
答案 7 :(得分:0)
您可以采取的另一项措施:用sb.Append(string.Format(...))
替换sb.AppendFormat(...)
来电。