Is this delegate usage good or bad?
This question is being asked because I have no prior experience with delegate best practices
I have a unordered lists in html, where the structure is the same throughout my site, but the content of the lists may differ.
Examples:
List of object A<ul>
<li>
<ul>
<li>A.someMember1</li>
<li>A.someMember2</li>
<li>A.someMember3</li>
</ul>
</li>
</ul>
List of object B
<ul>
<li>
<ul>
<li>B.someMember1</li>
<li>B.someMember2</li>
<li>B.someMember3</li>
<li>B.someMember4</li>
</ul>
</li>
</ul>
I created two delegates:
protected delegate void RenderHtmlMethod(HtmlTextWriter writer);
protected delegate void RenderHtmlMethodWithObjects(HtmlTextWriter writer, object obj);
and the following method
private void RenderList(HtmlTextWriter writer, string title, RenderHtmlMethod headingDelegate,
RenderHtmlMethodWithObjects itemsDelegate, object objToRender)
{
writer.RenderBeginTag(HtmlTextWriterTag.Fieldset);
writer.RenderBeginTag(HtmlTextWriterTag.Legend);
writer.HtmlEncode(title);
writer.RenderEndTag();//end Legend
writer.AddAttribute(HtmlTextWriterAttribute.Class, "resultList");
writer.RenderBeginTag(HtmlTextWriterTag.Ul);
{
headingDelegate(writer);
itemsDelegate(writer, objToRender);
}
writer.RenderEndTag();//ul
writer.RenderEndTag(); //fieldset
}
That way, I can make methods that render the heading (just another li with an embedded ul) and then render the necessary list items for each list of object.
I can't redefine my classes to implement any interfaces, although, I could create a wrapper for the classes and implement the render method there. What do you think about this?
Does my str开发者_JAVA技巧ucture make sense? Or am I insane?
I suppose it's not a bad decision. However, I think that better is to create special interface (or abstract class) which is used to generate your lists.
public abstract class ListRenderer
{
public abstract IEnumerable Items {get;}
public abstract String GenerateHeaderText();
public String GenerateItemText(objectItem);
public abstract void RenderList(TextWriter writer);
}
Then you just create your wrapper around your concrete items and pass this object to your generator method. If your list is build in a common way it's possible to implement all logic inside ListRenderer and then override only GenerateHeaderText and GenerateItemText
I'd go for a generic method Render(HtmlTextWriter)
and define all other parameters as properties of the class:
interface IRenderable
{
void Render(HtmlTextWriter writer);
}
class ListComponent : IRenderable
{
public List<IRenderable> Items { get; set; }
public string Title { get; set; }
public void Render(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Fieldset);
writer.RenderBeginTag(HtmlTextWriterTag.Legend);
writer.HtmlEncode(Title);
writer.RenderEndTag();//end Legend
writer.AddAttribute(HtmlTextWriterAttribute.Class, "resultList");
writer.RenderBeginTag(HtmlTextWriterTag.Ul);
foreach (var item in Items)
{
writer.RenderBeginTag(HtmlTextWriterTag.Li);
item.Render(writer);
writer.RenderEndTag();//li
}
writer.RenderEndTag();//ul
writer.RenderEndTag(); //fieldset
}
}
Why are you passing in delegates to perform the rendering? Do you want each list to be rendered slightly different? If you are looking for consistency, I would just pass the list of objects that you want to be rendered along with some header text and render it all inside your method. For example, my proposed method signature might be something like:
private void RenderList<T>(HtmlTextWriter writer, string title, string headerText, List<T> objectsToRender) where T : IRender
That being said, if every list really should be rendered in a unique manner, then I don't think you're any more insane than the voices in my head.
UPDATE
I guess I need to expand my code sample...
private void RenderList<T>(HtmlTextWriter writer, string title, string headerText, List<T> objectsToRender) where T : IRender
{
writer.RenderBeginTag(HtmlTextWriterTag.Fieldset);
writer.RenderBeginTag(HtmlTextWriterTag.Legend);
writer.HtmlEncode(title);
writer.RenderEndTag();//end Legend
writer.AddAttribute(HtmlTextWriterAttribute.Class, "resultList");
writer.RenderBeginTag(HtmlTextWriterTag.Ul);
{
writer.RenderBeginTag(HtmlTextWriterTag.Div); //begin Header
writer.AddAttribute(HtmlTextWriterAttribute.Class, "header");
writer.HtmlEncode(headerText);
writer.RenderEndTag(); //end Header
// render all objects
foreach (T obj in objectsToRender)
{
writer.RenderBeginTag(HtmlTextWriterTag.Li); // begin Custom Object Rendering
obj.CustomRender(writer);
writer.RenderEndTag(); // end Custom Object Rendering
}
}
writer.RenderEndTag();//ul
writer.RenderEndTag(); //fieldset
}
// IRender interface
public interface IRender
{
void CustomRender(HtmlTextWriter writer);
}
精彩评论