在Framework 2.0里微软提供了一个叫ClientScriptManager的类来专门管理Page类上面的脚本注册,并且把原来Page类上提供的RegisterXXX和IsRegisterXXX等方法都置为了Obsolete。ClientScriptManager类提供了一个叫RegisterExpandoAttribute()的新方法,不过这个方法实现得太草率了。
在Framework 2.0里微软提供了一个叫ClientScriptManager的类来专门管理Page类上面的脚本注册,并且把原来Page类上提供的RegisterXXX和IsRegisterXXX等方法都置为了Obsolete。ClientScriptManager类提供了一个叫RegisterExpandoAttribute()的新方法,不过这个方法实现得太草率了。
方法ClientScriptMarager.RegisterExpandoAttribute()有两个重载,分别是:
ClientScriptManager.RegisterExpandoAttribute (String, String, String)
ClientScriptManager.RegisterExpandoAttribute (String, String, String, Boolean) // 参数分别是:controlId, attributeName, attributeValue和encode。
这个方法是干什么的呢?它是用来
动态的向HTML元素添加
Expando属性的,我们在Fx 1.1时代,如果要在控键的输出标签上添加Expando属性,一般的方法是使用WebControl.Attributes集合属性,并且只能添加static的literal string。而在2.0里,我们就可以使用RegisterExpandoAttribute方法来达到同样的效果,其实效果和Fx1.1中一样,只是后者更突出了动态添加的概念。
比如在页面上放一个叫lblTest的Label控件,使用:
this.ClientScript.RegisterExpandoAttribute("lblTest", "message", "ok.");
this.ClientScript.RegisterExpandoAttribute("lblTest", "resulte", "'string'");
this.ClientScript.RegisterExpandoAttribute("lblTest", "resulte", "'string'", false);
我们得到如下的客户端注册脚本:

<script type="text/javascript">
<!--
var lblTest = document.all ? document.all["lblTest"] : document.getElementById("lblTest");
lblTest.message = "ok.";
lblTest.resulte = "\'string\'";
lblTest.resulte2 = "'string'";
// -->
</script> 看起来效果不错,但我为什么说它实现的很草率呢?Review一下微软的实现先:
internal void RenderExpandoAttribute(HtmlTextWriter writer)


{
if ((this._registeredControlsWithExpandoAttributes != null) && (this._registeredControlsWithExpandoAttributes.Count != 0))

{
writer.Write("\r\n<script type=\"text/javascript\">\r\n<!--\r\n");
foreach (DictionaryEntry entry1 in this._registeredControlsWithExpandoAttributes)

{
string text1 = (string) entry1.Key;
writer.Write("var ");
writer.Write(text1);
writer.Write(" = document.all ? document.all[\"");
writer.Write(text1);
writer.Write("\"] : document.getElementById(\"");
writer.Write(text1);
writer.WriteLine("\");");
ListDictionary dictionary1 = (ListDictionary) entry1.Value;
foreach (DictionaryEntry entry2 in dictionary1)

{
writer.Write(text1);
writer.Write(".");
writer.Write(entry2.Key);
if (entry2.Value == null)

{
writer.WriteLine(" = null;");
continue;
}
writer.Write(" = \"");
writer.Write(entry2.Value);
writer.WriteLine("\";");
}
}
writer.Write("// -->\r\n</script>\r\n");
}
}
既然说M$实现得很草率,那么死结在哪里呢?死结就是这个Expando Attribute,什么是expando呢?Expando实际上是DHTML对象本身的一种特性的描述,就是说我们可以向DHTML对象动态的添加任意的属性和属性值,其实就类似一个hashtable。
Expando在JScript中的使用,有两种方式。如果我们有:
var obj =
new Object(); 那么obj.xxx = 10; 和obj['xxx'] = 10; 所表现的效果是完全相同的。但是obj.xxx方式使用expando特性,只是JScript给我们的一个syntax sugar,实际上JScript解析引擎会自动把obj.xxx转换成obj['xxx']。而且obj[key]方式中的key,是任意的字符串或可转换为字符串的任意表达式。也就是说obj['0123456789'] = 10; obj['!@#$%^&*()'] = 10; obj['?><{}[]'] = 10; 都是合法的expando特性使用,只是他们不能写成obj.xxx这种形式。显然如果写成obj.xxx形式,obj.0123456789、
obj.!@#$%^&*()、obj.?><{}[],那么JScript的语法就全乱套了。
知道了expando特型的实际意义,再来看RegisterExpandoAttribute()方法?是不是实现的很草率呢?这个方法不该使用"."运算符来访问expando属性,而应该使用"[]"运算符。
BTW: 在JScript.NET中,expando作为一个修饰符出现,这时的具有expando特性的对象,只能使用"[]"运算符设置和访问expando属性了,并且分别表示不同属性值的obj.xxx还可以和obj.['xxx']共存于一个对象中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器