【问题标题】:Is this delegate usage good or bad?这个委托使用是好是坏?
【发布时间】:2009-10-15 14:23:22
【问题描述】:

之所以提出这个问题,是因为我之前没有代理最佳实践方面的经验

我在 html 中有一个无序列表,整个网站的结构都相同,但列表的内容可能不同。

示例:
对象A列表

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

对象B列表

<ul>
  <li>
    <ul>
      <li>B.someMember1</li>
      <li>B.someMember2</li>
      <li>B.someMember3</li>
      <li>B.someMember4</li>
    </ul>
  </li>
</ul>

我创建了两个代表:

protected delegate void RenderHtmlMethod(HtmlTextWriter writer);
protected delegate void RenderHtmlMethodWithObjects(HtmlTextWriter writer, object obj);

还有下面的方法

    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

    }

这样,我可以创建渲染标题的方法(只是另一个带有嵌入 ul 的 li),然后为每个对象列表渲染必要的列表项。

我无法重新定义我的类来实现任何接口,不过,我可以为这些类创建一个包装器并在那里实现渲染方法。您对此有何看法?

我的结构有意义吗?还是我疯了?

【问题讨论】:

  • 我们可以给标签投票吗?
  • “投票赞成”是什么意思?
  • 你可以用它来投票;)
  • +1 表示 am-i-insane 标签。我个人会使用 UserControl 而不是自定义控件,但我认为您对委托的使用没有任何反对意见。
  • @Gabe Moothart:我个人会使用 UserControl 而不是自定义控件您会以何种方式使用 UserControl?带中继器?

标签: c# templates delegates


【解决方案1】:

我想这不是一个糟糕的决定。但是,我认为更好的是创建用于生成列表的特殊接口(或抽象类)。

public abstract class ListRenderer
{
  public abstract IEnumerable Items {get;}
  public abstract String GenerateHeaderText();
  public String GenerateItemText(objectItem);
  public abstract void RenderList(TextWriter writer);
}

然后您只需围绕具体项目创建包装器并将此对象传递给您的生成器方法。如果您的列表以通用方式构建,则可以在 ListRenderer 中实现所有逻辑,然后仅覆盖 GenerateHeaderText 和 GenerateItemText

【讨论】:

  • 我选择了这个,因为它在实现时比我以前的解决方案更有条理。我选择创建一个界面
【解决方案2】:

我会选择通用方法Render(HtmlTextWriter) 并将所有其他参数定义为类的属性:

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

【讨论】:

    【解决方案3】:

    为什么要传递委托来执行渲染?您是否希望每个列表呈现略有不同?如果您正在寻找一致性,我只会传递您想要呈现的对象列表以及一些标题文本,并将其全部呈现在您的方法中。例如,我提出的方法签名可能是这样的:

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

    话虽如此,如果每个列表都真的应该以独特的方式呈现,那么我认为你不会比我脑海中的声音更疯狂。

    更新

    我想我需要扩展我的代码示例...

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-09
      • 1970-01-01
      相关资源
      最近更新 更多