3

イベントの作成とマルチスレッドアプリケーションの作成について学んでいます。

このメソッドThreadは、パラメータに検索条件を設定する別のクラスによって呼び出されます。ABackgroundWorkerが作成され、検索が実行され、結果がに返されますworker_RunWorkerCompleted

内で、イベントworker_RunWorkerCompletedをサブスクライブしているUIに結果を送り返したいと思います。Fireendofsearch

以下のコードが次のエラーをスローする理由を理解するのに問題があります

オブジェクト参照がオブジェクト インスタンスに設定されていません。

イベントを起動するときFireendofsearch

public class BackgroundSearch
{
    public event SearchResultCompleteThreaded Fireendofsearch;
    public EventArgs a = null;
    public delegate void SearchResultCompleteThreaded(object seachresults, EventArgs a);
    internal void Thread(string folder, string parms)
    {
        var Argument = new List<object> { folder, parms };
        var worker = new BackgroundWorker {WorkerReportsProgress = false, WorkerSupportsCancellation = false};
        worker.DoWork += worker_DoWork;          
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        worker.RunWorkerAsync(Argument);
    }
    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        var passedAugue = e.Argument as List<object>;
        var returnResult = new List<string[]>();
        if (passedAugue != null)
        {
            var result = Directory.GetFiles(passedAugue[0].ToString(), passedAugue[1].ToString(), SearchOption.AllDirectories);
            foreach (string s in result)
            {
                var t = new string[4];
                t[0] = s;
                t[1] = File.GetCreationTime(s).ToString();
                t[2] = File.GetLastAccessTime(s).ToString();
                t[3] = File.GetLastWriteTime(s).ToString();
                returnResult.Add(t);
            }
        }
        if (returnResult.Count != 0)
        {
            e.Result = returnResult;
        }            
    }
    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Result != null)
        {
            Fireendofsearch(e.Result, a);
        }
    }
}
4

5 に答える 5

2

Firendofsearchは、誰かがサブスクライブするまでnullになります。これを修正するには、作業完了イベントハンドラーをこれに変更してください。

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Result != null)
    {
        var friendOfSearch = Fireendofsearch;
        if(friendOfSearch != null)
           friendOfSearch (e.Result, a);
    }
}

私がそれを変数にコピーする理由は、別のスレッドの誰かがnullチェックとイベントの発生の間にサブスクライブを解除する最後の人である場合でも、最初に別の変数に対処することでその問題を解決するため、null参照例外が発生するためです。


ただし、他の変更を加える場合は、EventArgs何らかの理由でnullを再調整し、その結果を従来のイベントパターンの「送信者」として返します。私はあなたのコードをこれに変更します

public event EventHandler<FriendOfSearchArgs> FirendsOfSearch;

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Result != null)
    {
        RaiseFriendOfSearch(e.Result);
    }
}

protected virtual void RaiseFriendOfSearch(object result)
{
    var friendOfSearch = FirendsOfSearch;
    if(friendOfSearch != null)
        friendOfSearch(this, new FriendOfSearchArgs(result));
}


public class FriendOfSearchArgs : EventArgs
{
   public FriendOfSearchArgs(object result)
   {
       Result = result;
   }

   public object Result {get; private set;}
}

これはすべてSOテキストボックスに書き込まれているため、1つまたは2つのエラーが発生する可能性があります。

于 2012-11-04T17:54:33.613 に答える
0

何らかの理由で(最適化の可能性が最も高い)、イベントは、最初のハンドラーメソッドがサブスクライブしたときにのみインスタンス化されます。

コードでそれを確認する必要があります。

通常、イベントを宣言する方法は次のとおりです。

public event SearchResultCompleteThreaded Fireendofsearch;

private void RaiseFireEndOfSearchEvent(EventArgs e)
{
    if (Fireendofsearch != null)
    {
       Fireendofsearch(this, e);
    }
}

そして、イベントを発生させる必要があるときはいつでも、代わりにヘルパーメソッドを呼び出すだけです。

于 2012-11-04T17:54:45.153 に答える
0

デリゲートを呼び出す前に、nullをチェックする必要があります。また、スレッドの問題を回避するために、最初にそれを別の変数にプルする必要があります。

var ev = Fireendofsearch;
if ( ev != null ) ev( ... );

また、この場合の拡張メソッドがあると便利です。

public static void Raise ( this EventHandler h, object sender )
{
    if ( h != null) h( sender, EventArgs.Empty );
}

その後:

MyEvent.Raise ( this );
于 2012-11-04T18:01:03.603 に答える
0

パブリックイベントの「背後」には、タイプの暗黙的なプライベート変数がありSearchResultCompleteThreadedます。タイプSearchResultCompleteThreadedはデリゲートタイプです。

.NETでは、すべてのデリゲートは「マルチキャスト」デリゲートです。つまり、呼び出しリストがあります(GetInvocationList()上のメソッドSearchResultCompleteThreadedはから派生していSystem.Delegate.GetInvocationList()ます。

現在、.NETでは、呼び出しリストは1つ以上の項目(0個以上ではない)で構成されることが保証されいますすべてのデリゲート型は不変型です。var newDel = oldDel - oldDel;ただし、またはのように、既存のインスタンスの呼び出しリスト内のすべてのメンバーを「減算」して新しいインスタンスを作成しようとすると、reuseDel -= reuseDel;長さがゼロの呼び出しリストを持つ新しいインスタンスを取得する代わりに、null参照を取得します。

これの良いところは、「空の」デリゲートインスタンス(そうでなければ許可されていた可能性があります)とnull参照の微妙な違いについて心配する必要がないことです。それについての悪いことは、あなたが上で持っていた問題です。

于 2012-11-04T18:29:46.047 に答える
-1

セットする:

public event SearchResultCompleteThreaded Fireendofsearch =  delegate { };

おそらく初期化する必要がありますか?

于 2012-11-04T17:47:09.383 に答える