c#System.InvalidOperationException

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15410700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 16:44:05  来源:igfitidea点击:

c# System.InvalidOperationException

c#asynchronoustcpclient

提问by Brin

General

一般的

I'm trying to write a very simple TCPIP client server in C# to connect to an IP Address, with a port number, and ask quite simple line commands, and then place the replies in a Gridbox, graph or other display option.

我正在尝试用 C# 编写一个非常简单的 TCPIP 客户端服务器来连接到一个 IP 地址,带有一个端口号,并询问非常简单的行命令,然后将回复放在网格框、图形或其他显示选项中。

I have looked online and found a down loadable utility that does just this, written by Jayan Nair, and this appears to send the message correctly, and receive the reply ok.

我在网上查看并找到了一个可下载的实用程序,它可以执行此操作,由 Jayan Nair 编写,这似乎可以正确发送消息,并且可以正常接收回复。

The problem comes when I try and load the reply data into a richtext or GridView.

当我尝试将回复数据加载到富文本或 GridView 时,问题就出现了。

The error message I'm getting is :- System.InvalidOperationException

我收到的错误消息是:- System.InvalidOperationException

I have asked Microsoft Forums, and they have given me a very complicated, ambiguous and overly involved indication as to what I should do, and this involves something called INVOKE and BeginInvoke, and they whole things seems to be a project in it;s own right.

我问过微软论坛,他们给了我一个非常复杂、模棱两可且过于复杂的指示,告诉我我应该做什么,这涉及到一个叫做 INVOKE 和 BeginInvoke 的东西,他们整个事情似乎都是一个项目;对。

What I'm after is just an example that works, without being too complicated.

我所追求的只是一个有效的例子,不会太复杂。

Here's the code :-

这是代码:-

        try
        {
            SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
            int iRx = theSockId.thisSocket.EndReceive(asyn);
            char[] chars = new char[iRx + 1];
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
            // 
            System.String szData = new System.String(chars);
            richTextRxMessage.Text =  szData;  // fails
            //textBox1.Text = szData;          // also fails
            WaitForData();
        }

and here's the error message :-

这是错误消息:-

base {System.Windows.Forms.TextBoxBase} = {Text = '((System.Windows.Forms.RichTextBox)    (((System.Windows.Forms.RichTextBox)(richTextRxMessage)))).Text' threw an exception of type   'System.InvalidOperationException'}

Additional information is :-szData contains about 6300 characters, including tabs (9) and returns (13), and is consistant with the message sent from the server I've also tried it with using a textbox instead of richtext, same result

附加信息是:-szData 包含大约 6300 个字符,包括制表符 (9) 和返回 (13),并且与从服务器发送的消息一致我也尝试过使用文本框而不是富文本,结果相同

For those interested

对于那些有兴趣的人

Here's the Microsoft link

这是微软的链接

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/12a67fb0-847e-4e2b-baa8-ef6ceed60aa4/

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/12a67fb0-847e-4e2b-baa8-ef6ceed60aa4/



  • Here is just 2 of the code amendments that I've tried, both fail on the same error condition
  • 这里只是我尝试过的 2 个代码修改,都在相同的错误条件下失败
  • I think what I need to do is start C# at a much lower level and not just jump in and hope for the best


       public void OnDataReceived(IAsyncResult asyn)
        {
    
            int InputRx;
            int charLen;
            char[] Inputchars;
            System.Text.Decoder InputDecode;
            System.String szData;
            bool IfInvokeRequired;
    
            try
    
            {
    
                SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
                InputRx = theSockId.thisSocket.EndReceive(asyn);                    // get size of input array
                Inputchars = new char[InputRx + 1];                                   // put i char array
                InputDecode = System.Text.Encoding.UTF8.GetDecoder();
                charLen = InputDecode.GetChars(theSockId.dataBuffer, 0, InputRx, Inputchars, 0);
                szData = new System.String(Inputchars);
                IfInvokeRequired = richTextRxMessage.InvokeRequired;
                if (IfInvokeRequired == true)
                {
                    richTextRxMessage.Invoke((MethodInvoker)delegate { this.Text = szData; });// fails
                    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));//fails as well
                }
    
  • 我认为我需要做的是在低得多的级别开始 C#,而不仅仅是跳进去并希望最好


       public void OnDataReceived(IAsyncResult asyn)
        {
    
            int InputRx;
            int charLen;
            char[] Inputchars;
            System.Text.Decoder InputDecode;
            System.String szData;
            bool IfInvokeRequired;
    
            try
    
            {
    
                SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
                InputRx = theSockId.thisSocket.EndReceive(asyn);                    // get size of input array
                Inputchars = new char[InputRx + 1];                                   // put i char array
                InputDecode = System.Text.Encoding.UTF8.GetDecoder();
                charLen = InputDecode.GetChars(theSockId.dataBuffer, 0, InputRx, Inputchars, 0);
                szData = new System.String(Inputchars);
                IfInvokeRequired = richTextRxMessage.InvokeRequired;
                if (IfInvokeRequired == true)
                {
                    richTextRxMessage.Invoke((MethodInvoker)delegate { this.Text = szData; });// fails
                    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));//fails as well
                }
    
  • 回答by Nevyn

    The Microsoft answer is not entirely incorrect, but there are other ways to do it that are somewhat simpler, although they dont look it.

    Microsoft 的回答并非完全不正确,但还有其他更简单的方法,尽管它们看起来并不像。

    Here is a snippit from my own code that might come in handy for you.

    这是我自己的代码中的一个片段,可能对您有用。

    if (dirtyImage.InvokeRequired)
    {
        dirtyImage.Invoke(new MethodInvoker(delegate { Visible = RigX.IsDirty; }));
        dirtyImage.Invoke(new MethodInvoker(delegate { Refresh(); }));
    }
    else
    {
        dirtyImage.Visible = RigX.IsDirty;
        dirtyImage.Refresh();
    }
    

    note how InvokeRequiredand the dirtyImage.Invoke(...)are used. I make it a lot simpler by creating the delegates and using a method invoker, that way I can make all the calls one liners. the delegate essentially creates a mini-method, which is then invoked using the MethodInvoker. Because the changes are on the UI thread though, they cannot be called from a background thread without using .Invoke, its not permitted.

    请注意如何使用InvokeRequireddirtyImage.Invoke(...)使用。通过创建委托并使用方法调用程序,我使它变得更加简单,这样我就可以将所有调用进行一次衬垫。委托本质上创建了一个迷你方法,然后使用 MethodInvoker 调用该方法。因为更改是在 UI 线程上进行的,所以不能在不使用的情况下从后台线程调用它们,这是.Invoke不允许的。

    The way your calls could be altered in this way is:

    您的呼叫可以通过这种方式改变的方式是:

    richTextRxMessage.Invoke(new MethodInvoker(delegate { Text =  szData; }));
    

    that call also works directly from the UI thread itself, so you dont actually NEED the if statement, but it terms of 'cost', its slower than calling the properties directly.

    该调用也直接从 UI 线程本身工作,因此您实际上不需要 if 语句,但它涉及“成本”,它比直接调用属性慢。

    Of Course, this only really makes a difference if you were on a background thread to begin with. If not, then you need to investigate the error itself. Perhaps there is something wrong with the text of the return, write it to a file and look at it, see if you can spot the problem. Try setting the text of the RTB manually, see if it even allows that to happen. etc etc and so on.

    当然,这只有在您开始使用后台线程时才会真正有所作为。如果没有,那么您需要调查错误本身。也许返回的文本有问题,将其写入文件并查看它,看看是否可以发现问题。尝试手动设置 RTB 的文本,看看它是否允许这种情况发生。等等等等等等。

    回答by User 12345678

    The InvalidOperationExceptionthat you receive will likely have the inner exception "The calling thread cannot access this object because a different thread owns it".

    InvalidOperationException您收到将可能有内部异常“调用线程不能因为不同的线程拥有它访问这个对象”。

    For the sake of debugging you can quickly set CheckForIllegalCrossThreadCallsto false. This will stop the run-time from throwing you an exception, however just because you're not receiving the exceptions does not mean that they are not happening so this is a bad practice for distributed software but very handy for debugging.

    为了调试,您可以快速设置CheckForIllegalCrossThreadCalls为false。这将阻止运行时向您抛出异常,但是仅仅因为您没有收到异常并不意味着它们没有发生,因此这对于分布式软件来说是一种不好的做法,但对于调试非常方便。

    In order to resolve your issue you need to invoke the code that interacts with the RichTextBoxon the UI Threadaka the thread the control was created on and the only thread that is allowed to run code that interacts with the control.

    为了解决你的问题,你需要调用的代码与交互RichTextBoxUI线程又名控制是在创建线程,并且允许运行代码的唯一线程与控件交互。

    To invoke the code on the UI Thread you can use the following, succinct statement:

    要调用 UI 线程上的代码,您可以使用以下简洁的语句:

    richTextRxMessage.BeginInvoke(new MethodInvoker(() => richTextRxMessage.Text = szData));
    

    Very simply, all you are doing here is passing the statement you wish to invoke on the UI Thread by means of a delegate.

    很简单,您在这里所做的就是通过委托传递您希望在 UI 线程上调用的语句。

    回答by Kami

    The issue is likely because of multi-threading as suggested on the MS forums. As you are requesting this operation in an asynchronous manner, it will create another thread that will handle the input so that you main application thread does not block.

    这个问题很可能是因为 MS 论坛上建议的多线程。当您以异步方式请求此操作时,它将创建另一个线程来处理输入,以便您的主应用程序线程不会阻塞。

    To overcome this issue you will have to Invokethe control whose property you wish to change. You need this, as your main application thread owns the UI, and any operation on the UI cannot be done from another thread.

    要解决这个问题,您将不得不Invoke更改您希望更改其属性的控件。您需要这个,因为您的主应用程序线程拥有 UI,并且不能从另一个线程完成 UI 上的任何操作。

    The invoke is not complicated, and can be done in a few lines.

    调用并不复杂,几行就可以完成。

    Change the following line

    更改以下行

    richTextRxMessage.Text =  szData;
    

    to

    richTextRxMessage.Invoke((MethodInvoker) delegate {this.Text = szData;});
    

    This code will ask the main ui thread to update the text for richTextRxMessagerather than doing it itself.

    此代码将要求主 ui 线程更新文本richTextRxMessage而不是自己更新文本。

    回答by Shane.C

    Here's a function I use in some of my stuff;

    这是我在一些东西中使用的函数;

    public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
    {
        if (@this.InvokeRequired)
        {
            @this.Invoke(action, new object[] { @this });
        }
        else
        {
            action(@this);
        }
    }
    

    It's pretty much a nice little method for dealing with any sort of invoke, and cuts down the lines of code when you're using it. To use it, simply use this;

    这几乎是处理任何类型调用的一个不错的小方法,并且在您使用它时减少了代码行。要使用它,只需使用它;

    Control.InvokeEx(f => control.DoStuff());
    

    So for example, you might use;

    例如,您可能会使用;

    richTextRxMessage.InvokeEx(f => richTextRxMessage.Text =  szData);
    

    Edit: As others have said, this error is more than likely due to accessing a control on a thread other than the one it was created on, which is why the invokes are required.

    编辑:正如其他人所说,此错误很可能是由于访问了线程上的控件而不是创建它的线程,这就是需要调用的原因。