在 .Net 3.5 中使用动态关键字

7
我已经使用Visual Studio 2013编写了这段代码,利用的是.NET v4.5。我现在遇到的问题是,我必须降级到.NET v3.5,并且dynamic关键字会因缺少程序集引用而出现错误。在.NET v3.5中是否有等效于“dynamic”的类型或者一种方法可以达到与下面相同的结果?
我以为我在这里找到了答案,但当我添加.Attributes或.Text属性修改时,var会报错。
private void CreateControl<T>(string objText,
                              Panel pnl,
                              string HTMLTag = "<td>",
                              string applicantID = "",
                              EventHandler hndl = null)
{
    pnl.Controls.Add(new LiteralControl(HTMLTag));
    dynamic obj = Activator.CreateInstance(typeof(T));
    obj.Text = objText;

    if (applicantID != string.Empty)
    {
        obj.Attributes.Add("ApplicantID", applicantID);
    }
    if (hndl != null)
    {
        obj.Click += new EventHandler(hndl);
    }

    pnl.Controls.Add(obj);
    pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
}

3
3.5版本中没有Dynamic关键字,可以使用object。说实话,除非您将dynamicinterop配合使用,否则您的设计可能存在问题。 - T.S.
"Object"关键字会导致相同的问题。告诉我没有“属性”|“文本”的定义。进一步的阐述可能会有帮助? - Volearix
1
它实例化的对象为什么需要是动态的?如果您将类型约束应用于某个“Control”基类/接口,似乎应该可以工作。 - 48klocs
@48klocs 这可能是对动态关键字的误用,但我不知道从泛型类中传递的<T>类型是什么。它可以是从asp:textbox到tinymce:textarea任何类型的东西。 - Volearix
你应该从同一个接口派生你的控件,而不是使用 T - T.S.
4个回答

5

不要试图在某种注定失败的方式下进行黑客攻击,由于.net v3.5中没有“动态”控件,我决定完全放弃这种方法并编写了一些重载。目前这种方法似乎更安全;工作方式相同,只是代码有点多...

    #region CreateControl() Overloads
            /// <summary>
            /// Creates a LinkButton control.
            /// </summary>
            /// <param name="objText">.Text property of this LinkButton control.</param>
            /// <param name="pnl">Panel this control will be attached to.</param>
            /// <param name="hndl">Event handler attached to this LinkButton control.</param>
            /// <param name="HTMLTag">Opening tag used to contain this control.</param>
            private void CreateControl(string objText,
                                       Panel pnl,
                                       EventHandler hndl,
                                       string HTMLTag)
            {
                pnl.Controls.Add(new LiteralControl(HTMLTag));
                LinkButton obj = new LinkButton();
                obj.Text = objText;
                obj.Click += new EventHandler(hndl);

                pnl.Controls.Add(obj);
                pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
            }
            /// <summary>
            /// Creates a Label control.
            /// </summary>
            /// <param name="objText">.Text property of this Label control.</param>
            /// <param name="pnl">Panel this control will be attached to.</param>
            /// <param name="HTMLTag">Opening tag used to contain this control.</param>
            private void CreateControl(string objText,
                                       Panel pnl,
                                       string HTMLTag)
            {
                pnl.Controls.Add(new LiteralControl(HTMLTag));
                Label obj = new Label();
                obj.Text = objText;

                pnl.Controls.Add(obj);
                pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
            }
            /// <summary>
            /// Creates the specified literal control.
            /// </summary>
            /// <param name="ControlText">HTML text containing instructions for creating the desired literal control.</param>
            /// <param name="pnl">Panel this literal control will be attached to.</param>
            private void CreateControl(string ControlText, 
                                       Panel pnl)
            {
                pnl.Controls.Add(new LiteralControl(ControlText));
            }
        #endregion

很高兴你解决了它;与“拼凑在一起”相比,你的解决方案更有意义。+1 - Dmitriy Khaykin
在 .Net 3.5 中,只需使用 ExpandoObject 替换 dynamic 即可。只需引用 System.Dynamic。 - Daniel Bardi

2
在.NET v3.5中没有与“dynamic”等效的类型。使用反射代替“dynamic”创建控件并添加事件处理程序可实现相同结果。但是,由于这似乎是您正在创建的几个自定义控件之一(考虑到属性等),因此您可以约束为接口或基类,这将允许您直接创建项目并使用那些共享属性。保留HTML标签。

你能指出使用反射完成此函数的参考资料吗?我在谷歌上搜索了一下,但不太理解。 - Volearix
@Volearix 你需要获取 PropertyInfo,然后使用 SetValue 来设置文本等-请参阅 http://msdn.microsoft.com/en-us/library/f7ykdhsy.aspx。 - Reed Copsey

0

根据您的代码,看起来您正在编写一个通用方法来传递一些未知的控件并将它们附加到面板。

同时,您似乎正在处理不同类型的控件;即,并非所有WebControls都具有Text、Attributes和Click属性;

这有点hacky,但在3.5中可以工作-您只需使用各种底层类型或接口的转换来访问所需的属性,类似于以下内容:

private void CreateControl<T>(string objText, Panel pnl, string HTMLTag, 
    string applicantID, EventHandler hndl)
        where T : Control, new()
{
    pnl.Controls.Add(new LiteralControl(HTMLTag));
    T obj = new T();

    if (obj is ITextControl) (obj as ITextControl).Text = objText;

    if (applicantID != string.Empty && obj is WebControl)
        (obj as WebControl).Attributes.Add("ApplicantID", applicantID);


    if (obj is IButtonControl)
    {
        (obj as IButtonControl).Text = objText;
        if (hndl != null)
        {
            (obj as IButtonControl).Click += new EventHandler(hndl);
        }
    }

    pnl.Controls.Add(obj as Control);
    pnl.Controls.Add(new LiteralControl(HTMLTag.Insert(1, "/")));
}

测试代码:

protected void Page_Load(object sender, EventArgs e)
{
    var panel = new Panel();

    CreateControl<Button>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
    CreateControl<Label>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
    CreateControl<Panel>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
    CreateControl<Literal>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));

    //This won't compile because object doesn't fit <control> constraint
    //CreateControl<object>("test", panel, "<td>", "123", (s, args) => Console.WriteLine("hello!"));
}

说实话,我不确定我是否喜欢这种方法。我可能会使用一些更具体的方法和可能的方法重载来更具体地创建不同类型的控件,但这可能有助于指导您朝正确的方向前进。
请注意,在配有 .NET 3.5 的 C# 3.0 中,“可选参数”也尚未“发明”,因此您必须实际传入所有值。

@T.S.:工厂确实是另一个选项。我在回答中声明,我不会这样做;然而,这段代码最接近 OP 尝试做的事情,并且可以在 .net 3.5 中编译。完全重构/重新架构 OP 的代码超出了 SO 的范围,不是吗?(尽管我承认当我提供一些答案时,如果显而易见,我会这样做)。在这里,这将像编写一堆全新的代码。 - Dmitriy Khaykin
你一直在进行双重转换,可以将其中一个转换为强制类型转换并检查是否为空!仅仅因为它适合单行显示,并不意味着它以任何方式都更快。 - Trevor Pilley
做到这一点的方法是将所有控件封装到一个公共接口中,而不是使用 CreateControl<T> (...),而是使用 CreateControl (IMySystemControl c, ...)。我告诉你,人们会得到关键字并随心所欲地使用它 :o) - T.S.
@T:S.: 然后他必须对所有控件进行子类化 - 这些是他正在使用的本地 asp.net 控件。然后,这些子类将实现一个通用接口,其中包含并非所有子类都会使用的属性,例如 Literal 控件上的 Click 事件。就个人而言,我也不喜欢那个想法。 - Dmitriy Khaykin
@DavidKhaykin,这与将Literal控件传递给CreateControl<T>并没有什么不同,并且没有单击。问题在于有人想要(并实现了)以统一的方式初始化一组控件。但是收益很小。如果我构建一个强大而可扩展的系统,我会统一所有控件,包括第三方控件,并检查它们是否为IClickableISelectable等。在这里,我们处理的是某人决定以酷的方式做到这一点,留下了可疑决策的痕迹。 - T.S.
显示剩余4条评论

-3

dynamic 关键字可用于 .net 4.x,是一种简单的存储任何类型值的方式,它可以在运行时解析其类型。在使用 JSON 字符串时,它对我非常有用。

string jsonValue = "{name:'Pedro',lastName:'Mora'}";
dynamic Variable = new JavascriptSerializer().Deserialize<dynamic>(jsonValue);
return Variable.name;
//It will return "Pedro"

问题在于你必须确保该值不会为空,并且属性、属性或方法或其他引用对象的内容存在并在运行时获取其值。


这并没有回答如何在 .NET 4.0 之前复制这种行为的问题,这正是问题所问的。 - Servy
@pedritin 这不是我的问题,请重新阅读。我需要一种动态的替代方案,而不是它的工作原理。 - Volearix
对不起,我只是说了我使用它并解释了它在运行时获取其类型。我认为你应该将其转换为对象,评估是否为空,然后获取其基本类型。然后加载类型的程序集,或者类似于此的东西。 - pedritin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接