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

Posted

技术标签:

【中文标题】在 .Net 3.5 中使用动态关键字【英文标题】:Use of Dynamic Keyword in .Net 3.5 【发布时间】:2014-03-17 08:54:15 【问题描述】:

我在 Visual Studio 2013 中使用 .net v4.5 编写了这段代码。我遇到的问题是我现在不得不下拉到 .net v3.5 并且动态关键字由于缺少程序集引用而引发错误。 .net v3.5 中是否有与“动态”等效的类型,或者我可以通过何种方式获得与以下相同的结果?

我想我可能已经找到答案 here,但是当我添加 .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.5 中没有 Dynamic 关键字。你可以使用object。老实说,除非您将dynamicinterop 结合使用,否则您的设计有问题` Object 关键字会导致同样的问题。告诉我“属性”|“文本”没有定义。进一步阐述可能会有所帮助? 它实例化的对象是否是动态的?如果您要将类型约束应用于某些 Control 基类/接口,它似乎应该可以工作。 @48klocs 这可能是对 dynamic 关键字的误用,但我不知道哪个类型 来自泛型类。它可以是从 asp:textbox 到 tinymce:textarea 的任何东西。 你应该做的是从同一个界面派生你的控件并使用它而不是T 【参考方案1】:

.net v3.5 中是否存在与“动态”等效的类型

没有。 dynamic 需要 .NET 4.0。

或者让我获得与以下相同结果的方法?

您可以使用反射而不是dynamic 来创建控件并添加您的事件处理程序。

但是,由于这似乎是您正在创建的几个自定义控件之一(给定属性等),您可以限制到一个接口或基类,这将允许您创建项目和直接使用这些共享属性。

【讨论】:

能否指点使用反射来完成这个功能的参考?我用谷歌搜索了它,并没有完全遵循。 @Volearix 您必须获取 PropertyInfo,然后使用 SetValue 设置文本等 - 参见 msdn.microsoft.com/en-us/library/f7ykdhsy.aspx【参考方案2】:

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 之前复制这种行为的问题,这就是问题所在。 @pedritin 这不是我的问题,请重新阅读。我需要动态的替代方案,而不是它的工作方式。 对不起。我只是说我使用它并解释它在运行时采用他的类型。我认为您应该将其转换为对象,评估 if is not null 然后获取其基本类型。加载类型的程序集,类似的东西。【参考方案3】:

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

看起来您正在处理不同类型的控件;即,并非所有 WebControl 都具有 Text、Attributes、AND 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!"));

说实话,我不是 100% 确定我喜欢这种方法。我可能会使用一些更具体的方法和可能的方法重载来更具体地创建不同类型的控件,但这可能有助于为您指明正确的方向。

请注意,optional parameters 还没有在 .net 3.5 附带的 C# 3.0 中“发明”,因此您必须实际传递所有值。

【讨论】:

没办法。那么,为什么不工厂呢? @T.S.:工厂肯定是另一个选择。我在回答中做出了免责声明,我不会这样做;但是,此代码最类似于 OP 正在尝试执行的操作,并且可以在 .net 3.5 中编译。完全重构/重构 OP 的代码超出了 SO 的范围,不是吗? (尽管我承认在我提供一些答案时我会这样做的地方非常明显)。在这里,它就像是编写了一堆全新的代码。 你一直在双重施法,做一个施法并检查是否为空!仅仅因为它适合单行,并不意味着它在任何方面都更快.. 这样做的方法是将所有控件包装到一个公共界面中,而不是 CreateControl&lt;T&gt; (...)CreateControl (IMySystemControl c, ...) 。我告诉你,人们得到关键字并用它做任何他们喜欢的事情:o) @T:S.:然后他必须对所有控件进行子类化——这些是他正在使用的原生 asp.net 控件。然后,子类将实现一个公共接口,该接口包含并非所有子类都使用过的属性,例如 Literal 控件上的 Click 事件。我个人也不喜欢这个想法。【参考方案4】:

我没有尝试以某种注定失败的方式将其组合在一起,而且由于 .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 相比,您的解决方案更有意义 只需在 .Net 3.5 中使用 ExpandoObject 代替动态。只需参考 System.Dynamic

以上是关于在 .Net 3.5 中使用动态关键字的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C# 在 ASP.NET 3.5 中动态设置“application/ld+json”Schema.org 元数据

var关键字

将代码从 .net 4.0 回滚到 .net 3.5,现在动态不起作用

在 c# .Net 3.5 中,如何控制多个 WaitHandles?

如何动态设置使用 SSL 的 .Net 3.5 Web 服务?

我可以在 Tornado-redis 中使用 async 和 await 吗? (Python 3.5)