Is this use of a delegate good or bad?

This question is being asked because I have no experience with delegate best practices.

I have unordered lists in html where the structure is the same on my site, but the content of the lists may be different.

Examples:
Object List A

<ul>
  <li>
    <ul>
      <li>A.someMember1</li>
      <li>A.someMember2</li>
      <li>A.someMember3</li>
    </ul>
  </li>
</ul>

      

Object List 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 next 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

    }

      

This way I can create methods that display a title (just another li with an inline ul) and then display the required list items for each list of objects.

I cannot override my classes to implement any interfaces, although I could wrap the classes and implement a render method there. What do you think about this?

Does my structure make sense? Or am I crazy?

+2


source to share


3 answers


I suppose this is not a bad decision. However, I find it better to create a custom interface (or abstract class) that 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 specific items and pass that object to your generator method. If your list is built in a generic way, it can implement all the logic inside the ListRenderer and then override only GenerateHeaderText and GenerateItemText

+4


source


Why are you passing the rendering to the delegates? Do you want each list to display a little differently? If you're looking for consistency, I'll just pass in a list of the objects you want to render along with some header text and render the whole thing inside your method. For example, my suggested method signature might look something like this:

private void RenderList<T>(HtmlTextWriter writer, string title, string headerText, List<T> objectsToRender) where T : IRender

      

If we say that if each list really needs to be presented in a unique way, then I don't think you are any crazier than the voices in my head.



UPDATE

I think I need to expand on the sample code ...

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);
}

      

0


source


I would go for the 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
    }
}

      

0


source







All Articles