返回查找对象所在列标

Downcasting is kind of something you usually want to avoid, but sometimes it's not easily avoided. It depends on the situation. Because it's not an idiom you'll find yourself doing every day, sometimes you'll forget to do it entirely and what you're looking for is right there under your nose.

垂头丧气通常是要避免的事情,但有时却不容易避免。 这取决于实际情况。 因为这不是惯用语,所以您会发现自己每天都在做,有时您会忘记完全这样做,而您所寻找的正是在您的鼻子底下。

问题 (The Problem)

A buddy was trying to host the WebBrowser control in his WinForms application. It was a locally run application that was using the WebBrowser control to generate part of the UI. The user might click on a link, and you'd want to do something based on the click of an link/anchor in the HTML.

一位好友正在尝试在他的WinForms应用程序中托管WebBrowser控件。 这是一个本地运行的应用程序,正在使用WebBrowser控件生成UI的一部分。 用户可能会单击一个链接,而您希望基于HTML中的链接/锚点单击来执行某些操作。

In this trivial example, I add the words "Add Comment" to a page I've navigated to within my WinForms Application.

在这个简单的示例中,我在WinForms应用程序中导航到的页面上添加了“添加注释”一词。

First, we make some new elements within the WebBrowser control itself, like this.

首先,我们在WebBrowser控件本身中制作了一些新元素,如下所示。

HtmlElement div = webBrowser1.Document.CreateElement("div");div.SetAttribute("style", "color:blue;");webBrowser1.Document.Body.AppendChild(div);

HtmlElement anchor = webBrowser1.Document.CreateElement("a");anchor.InnerText = "Add Comment";anchor.Id = "lnkAddComment";anchor.SetAttribute("href", "#");anchor.Click += new HtmlElementEventHandler(doit);div.AppendChild(anchor);

Notice that we can hook up a managed event handler to the anchor, and that the anchor's href attribute points to nothing, by setting it to "#".

请注意,我们可以将托管事件处理程序连接到锚点,并且通过将锚点的href属性设置为“#”,它的指向不指向任何内容。

anchor.Click += new HtmlElementEventHandler(doit);

My friend hooked up the event to doit() that had a standard EventHandler signature like this:

我的朋友将事件连接到具有标准EventHandler签名的doit(),如下所示:

public void doit(object sender, HtmlElementEventArgs e)

You've likely seen this "object sender, SomeEventArgs e" method signature before. He started digging around in the HtmlElementEventArgs object, trying to find something he could use to known if the user had clicked on the link called lnkAddComment. He was bummed to find nothing he could use.

您之前可能已经看过此“对象发送者,SomeEventArgs e”方法签名。 他开始在HtmlElementEventArgs对象中进行挖掘,试图找到他可以用来知道用户是否单击了名为lnkAddComment的链接的东西。 他为找不到任何可以使用的东西而感到沮丧。

There's a couple of thing to learn here. First, just hovering over the sender object in the debugger shows us a lot. We can see that the type of sender isn't just object, but rather System.Windows.Forms.HtmlElement. This is a CLR type, and not a JavaScript type or a type you'd know about if you were familiar with the DOM and were expecting something more DOM-like.

这里有几件事要学习。 首先,只需将鼠标悬停在调试器中的sender对象上,就会向我们展示很多东西。 我们可以看到发件人的类型不仅是对象,还包括System.Windows.Forms.HtmlElement。 这是CLR类型,不是JavaScript类型,也不是您熟悉DOM并期望更类似于DOM的类型时要知道的类型。

The DOM element in this case, is there, but it's a COM Object and is part of the IE DOM object model and you'd be better off using Visual Basic if you care deeply about getting into it as we've recently learned.

在这种情况下,存在DOM元素,但这是一个COM对象,并且是IE DOM对象模型的一部分,如果您像我们最近所学的那样,深入研究它,那么最好使用Visual Basic 。

垂头丧气,该死的地方! (Downcast, Damned Spot!)

However, it's an HtmlElement and it has and id property with the string "lnkAddComment," and that's useful. At this point one could down-cast it. That means, telling the compiler that we know more than it does and that we're totally sure and are willing to risk our necks.

但是,它是一个HtmlElement,它具有带有字符串“ lnkAddComment”的id属性,这很有用。 在这一点上,人们可以放下心来。 这意味着,告诉编译器我们知道的不止于此,并且我们完全确定并且愿意冒险。

HtmlElement foo = (HtmlElement)sender;if (foo.Id == "lnkAddComment"){   MessageBox.Show("woot");}

There's some interesting things we can think about here. First, what if we're wrong? Well, bad things for one:

我们可以在这里考虑一些有趣的事情。 首先,如果我们错了怎么办? 好吧,一件坏事:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidCastException: Unable to cast object of type 'Something.You.Did.Not.Plan.On' to type 'System.Windows.Forms.HtmlElement'.
   at WindowsFormsApplication1.Form1.doit(Object sender, HtmlElementEventArgs e) in C:\Yay\Form1.cs:line 32

System.Reflection.TargetInvocationException:调用的目标引发了异常。 ---> System.InvalidCastException:无法将类型为'Something.You.Did.Not.Plan.On'的对象转换为类型为“ System.Windows.Forms.HtmlElement”。 在WindowsFormsApplication1.Form1.doit(Object sender,HtmlElementEventArgs e)中的C:\ Yay \ Form1.cs:第32行

And that sucks. However, in this case we are pretty darn sure, but we should be more defensive about it.

那太糟了。 但是,在这种情况下,我们非常确定,但是我们应该对此采取防御措施。

public void doit(object sender, HtmlElementEventArgs e){   if (sender is HtmlElement)   {      HtmlElement foo = (HtmlElement)sender;      if (foo != null && foo.Id == "lnkAddComment")      {         MessageBox.Show("woot");      }   }}

But that is kind of verbose, we can try a defensive cast:

但这有点冗长,我们可以尝试防御性施法

HtmlElement foo = sender as HtmlElement;if (foo != null && foo.Id == "lnkAddComment"){   MessageBox.Show("woot");}

In this case, if sender isn't an HtmlElement, we'll get back null. The same code in VB is pretty clear also. See the TryCast?

在这种情况下,如果发件人不是HtmlElement,我们将返回null。 VB中的相同代码也很清楚。 看到TryCast吗?

Public Sub doit(ByVal sender As Object, ByVal e As HtmlElementEventArgs)    Dim foo As HtmlElement = TryCast(sender,HtmlElement)    If ((Not foo Is Nothing) AndAlso (foo.Id = "lnkAddComment")) Then        MessageBox.Show("woot")    End IfEnd Sub

The IL (Intermediate Language) instructions are interesting also as it's asking explicitly if that object is what I think it is:

IL(中间语言)指令也很有趣,因为它明确询问该对象是否是我认为的对象:

L_0001: ldarg.1 L_0002: isinst [System.Windows.Forms]System.Windows.Forms.HtmlElement

I suppose that means I could just ask myself, but that's largely stylistic as the resulting IL is virtually the same, with the defensive cast being a simpler.

我想这意味着我可以问问自己,但这在很大程度上是风格上的,因为最终的IL几乎是相同的,而防守阵容则更为简单。

但是,为什么完全垂头丧气呢? (But Why the Downcast at All?)

At this point you might be asking, Why did I have to downcast at all? Doesn't that mean the EventHandler pattern is lame? Maybe, but here's the thinking as described by Jeffrey Richter on page 228 of his most excellent CLR via C#, 2nd Edition (with [contextual edits and emphasis] by me so it makes sense in this post).

在这一点上,您可能会问,为什么我必须全部放弃? 这不是说EventHandler模​​式是la脚的吗? 也许可以,但是这是杰弗里·里希特(Jeffrey Richter)在他最出色的CLR(通过C#,第二版)的第228页上描述的想法(我对此进行了[上下文编辑和强调],因此在本帖子中是有意义的)。

A lot of people wonder why the event pattern requires the sender parameter to always be of type Object. After all, since the [HtmlElement] will be the only type raising an event with a [HtmlElementEventArgs] object, it makes more sense for the callback method to be prototyped like this:

许多人想知道为什么事件模式要求sender参数始终为Object类型。 毕竟,由于[HtmlElement]将是唯一一个引发带有[HtmlElementEventArgs]对象的事件的类型,因此对回调方法进行如下原型设计更有意义:

void MethodName(HtmlElement sender, HtmlElementEventArgs e);

void MethodName(HtmlElement sender,HtmlElementEventArgs e);

The pattern requires the sender parameter to be of type Object mostly because of inheritance. What if [HtmlElement] were used as a base class for [DerivedHtmlElemen]? In this case, the calIback method should have the sender parameter prototyped as an [DerivedHtmlElement] instead of HtmlElement, but this can't happen because [DerivedHtmlElement] just inherited the Click event. So the code that was expecting an [DerivedHtmlElement] to raise the event must still have to cast the sender argument to an [DerivedHtmlElement]. In other words, the cast is still required, so the sender parameter might as well be typed as Object.

该模式要求sender参数的类型为Object,主要是因为继承。 如果将[HtmlElement]用作[DerivedHtmlElemen]的基类怎么办? 在这种情况下,calIback方法应该将发送者参数原型化为[DerivedHtmlElement]而不是HtmlElement,但这不会发生,因为[DerivedHtmlElement]刚刚继承了Click事件。 因此,期望[DerivedHtmlElement]引发事件的代码仍然必须将sender参数强制转换为[DerivedHtmlElement]。 换句话说,仍然需要强制转换,因此sender参数也可以键入为Object。

The next reason for typing the sender parameter as Object is just flexibility. It allows the delegate to be used by multiple types that offer an event that passes a [HtmlElementEventArgs] object. For example, a [PopHtmlElement] class could use the delegate even if this class were not derived from [HtmlElement].

将sender参数键入为Object的下一个原因仅仅是灵活性。 它允许委托由提供通过[HtmlElementEventArgs]对象的事件的多种类型使用。 例如,即使不是从[HtmlElement]派生的类,[PopHtmlElement]类也可以使用委托。

One more thing: the event pattern also requires that the delegate definition and the callback method name the EventArgs-derived parameter e. The only reason for this is to add additional consistency to the pattern, making it easier for developers to learn and implement the pattern. Tools that spit out source code (such as Microsoft Visual Studio) also know to call the parameter e.

还有一件事:事件模式还要求委托定义和回调方法将EventArgs派生参数e命名。 这样做的唯一原因是为模式增加了额外的一致性,从而使开发人员更容易学习和实现模式。 吐出源代码的工具(例如Microsoft Visual Studio)也知道调用参数e。

If you're interested in this kind of stuff, you should totally buy his book.

如果您对这种东西感兴趣,应该完全买他的书。

我们可以完全避免演员阵容吗? (Can we avoid the cast completely?)

Why did we downcast in the first place? We wanted to get ahold of the HtmlElement.Id property so we could do a string comparison in order to tell if an object is the one we're looking for. Perhaps we can check for that object's identity using something a little cleaner than a string.

我们为什么首先要灰心呢? 我们想要获取HtmlElement.Id属性,以便可以进行字符串比较,以判断对象是否就是我们要寻找的对象。 也许我们可以使用比字符串更干净的东西来检查对象的身份。

In this case, since we were the ones that created the anchor in the first place we can check the "object sender" against a saved reference to our anchor by checking object identity. Are these the same two objects? Is the object I added to the object model the same one that is coming back to me as the sender parameter to this Event Handler?

在这种情况下,由于我们是首先创建锚的人,因此可以通过检查对象身份来对照保存的对锚的引用来检查“对象发送者”。 这两个对象是相同的吗? 我添加到对象模型中的对象是否与作为该事件处理程序的sender参数返回给我的对象相同?

HtmlElement anchor;public void doit(object sender, HtmlElementEventArgs e){   if (sender.Equals(anchor))   {      MessageBox.Show("woot");   }}

Is this a good idea? What about using == instead? In this case, I CAN use == because HtmlElement has explicitly created equality operators, so when I'm using == to compare these two instances I'm ACTUALLY calling a static op_Equality(HtmlElement, HtmlElement) on the HtmlElement type. It's static because both side might be null and I can't call methods on null instances.

这是一个好主意吗? 那用==代替呢? 在这种情况下,我可以使用==,因为HtmlElement已显式创建了相等运算符,所以当我使用==比较这两个实例时,我实际上是在HtmlElement类型上调用静态op_Equality(HtmlElement,HtmlElement)。 这是静态的,因为双方都可能为空,并且我无法在空实例上调用方法。

HtmlElement anchor;public void doit(object sender, HtmlElementEventArgs e){   if (anchor == sender)   {      MessageBox.Show("woot");   }}

However, while operator overloading is common in C++ it's generally considered to be unnecessarily obscure in C# and moreover, you just can't count on folks to be consistent. For example, when I say == do I mean value equality or reference equality? In the case of HtmlElement they mean reference equality. In C++ an overloaded == is usually done for deep value comparisons.

但是,尽管运算符重载在C ++中很常见,但在C#中通常被认为是不必要的晦涩难懂,而且,您只是不能指望人们保持一致。 例如,当我说==时,是指值相等还是引用相等? 对于HtmlElement,它们表示引用相等。 在C ++中,通常对深层值进行重载==。

I will get this warning if I try anyway:

如果我仍然尝试,我将收到此警告:

Possible unintended reference comparison; to get a value comparison, cast the right hand side to type 'System.Windows.Forms.HtmlElement'

可能的意外参考比较; 若要进行值比较,请在右侧键入“ System.Windows.Forms.HtmlElement”

I like to use Equals() myself for clarity's sake, but touché! It's going to just do this internally anyway:

为了清楚起见,我喜欢自己使用Equals(),但请触摸! 无论如何都将在内部执行此操作:

public override bool Equals(object obj){    return (this == (obj as HtmlElement));}

Commenter Adam makes the excellent point that using Object.ReferenceEquals is explicitly clear in expressing intent. The result would be:

评论员Adam指出,使用Object.ReferenceEquals明确表达意图很明显。 结果将是:

public void doit(object sender, HtmlElementEventArgs e){       if (Object.ReferenceEquals(anchor,sender))       {               MessageBox.Show("woot");       }}

Of course, the implementation of ReferenceEquals is just this again. ;)

当然,ReferenceEquals的实现仅此而已。 ;)

public static bool ReferenceEquals(object objA, object objB){    return (objA == objB);}

What's the point?

重点是什么?

Know your options, but above all, know your intentions and make sure that the code you're writing correctly expresses your intent.

了解您的选择,但首先要了解您的意图,并确保所编写的代码正确表达了您的意图。

翻译自: https://www.hanselman.com/blog/back-to-basics-this-is-not-the-object-youre-lookingwait-oh-it-is-the-object

返回查找对象所在列标

返回查找对象所在列标_返回基础-这不是您要查找的对象...等等,哦,它是对象...相关推荐

  1. python返回字符在字符串的位置_返回单词在字符串中的位置的函数

    我正在编写一个接受两个参数的函数:asearch string和target string.函数将在目标字符串中查找搜索字符串,并应返回一个字符串,该字符串表示在目标字符串中找到搜索字符串的位置.在 ...

  2. php接口返回一个数组怎末写_返回php数组

    PHP数组简介 v 一.PHP数组的分类 按照下标的不同,PHP中的数组分为关联数组和索引数组: 索引数组:下标从0开始,依次增长. $arr=[1,2,3,4,5]; 关联数组:下标为字符串格式,每 ...

  3. 如何添加引文标_如何在Google文档中查找和添加引文

    如何添加引文标 When writing papers, you need to generate a detailed and accurate list of all the sources yo ...

  4. Lisp获取偏置后对象的坐标点_三坐标测量基础知识2020

    三坐标学习的几点忠告 RationalDMIS7.0实战从入门到精通 2019(新书售卖) 一.测头的选择 1.在测量方案的设计中,尽量选用最少的测头个数,对于MH20I,PH10T,PH10M,RE ...

  5. 查找字符串中指定字符的位置c语言,C语言中查找字符在字符串中出现的位置的方法...

    C语言strchr()函数:查找某字符在字符串中首次出现的位置 头文件:#include strchr() 用来查找某字符在字符串中首次出现的位置,其原型为: char * strchr (const ...

  6. python输入日期计算天数_用python计算日期(1、返回指定日期所在的一周,2,计算一个日期的月份和天数加减)...

    放两个小轮子吧,欢迎测试bug,然后告诉我: 1.返回指定日期所在的一周 2,计算一个日期的月份和天数加减 # -*- coding: utf-8 -*- """ Cre ...

  7. java返回空集合对象_返回null或空集合更好吗?

    这是一个普遍的问题(但是我正在使用C#),最好的方法是什么(最佳实践),对于以集合为返回类型的方法,您是否返回null或空集合? #1楼 我想在这里举例说明. 在这里考虑一个案例. int total ...

  8. mysql自定义函数update返回值_返回update

    PostgreSQL update returning NEW|OLD column value 在对账|购票|防纂改|原子操作中的妙用 标签 PostgreSQL , update , return ...

  9. 主线程如何等待多线程完成 返回数据_多线程基础体系知识清单

    作者:Object 来源:https://juejin.im/user/5d53e1f6f265da03af19cae0/posts 前言 本文会介绍Java中多线程与并发的基础,适合初学者食用. 线 ...

最新文章

  1. 使用B::Deparse模块对perl代码反汇编
  2. SpringBoot异常处理ErrorController详解
  3. mysql 回表查询优化_MySQL优化:如何避免回表查询?什么是索引覆盖?
  4. Java –手工Classloader隔离
  5. 软考系统架构师笔记-综合知识重点(一)
  6. oracle跨数据库用户操作,ORACLE跨数据库操作,DBLINK的使用
  7. str split函数 php,怎么在php中利用str_split函数分割字符串
  8. 设备像素比devicePixelRatio简单介绍
  9. java 数组 源码_Java数组转List的三种方式及对比
  10. mysql like BR%._MySQL Like子句
  11. window 下tomcat 内存设置,bat启动方式的
  12. 【人脸识别】基于matlab GUI SVM和PCA人脸识别【含Matlab源码 369期】
  13. 电阻式触摸屏和电容式触摸屏区别
  14. 【转载】教你怎么将centos7打造成桌面系统
  15. Vue3快速学习、vue3视频学习、vue3实例上手教程
  16. PC版微信自动回复工具
  17. 几何语言点C是ab的中点,数学几何定理符号语言
  18. 2023西湖论剑wirteup
  19. 程序员的奋斗史(四十一)——大学断代史(五)——我的娱乐方式
  20. 如何禁用Windows更新

热门文章

  1. MAE TransMix
  2. 基于DTMF技术与射频技术的远程控制的实现
  3. 解决Past duration X.XXXX too large警告
  4. 使用Git从gitee仓库中,只下载其中的某单个的文件夹
  5. 随机生成一个质数的python代码_python3 随机数 质数 素数 文件操作
  6. Christian band介绍
  7. [python] NetworkX实例
  8. pk 与fk mysql_什么是MySQL FK的正确命名约定?
  9. Scala class和case class的区别
  10. adwords与adsence