Отвечать на события из списка экземпляров классов - PullRequest
0 голосов
/ 21 января 2011

У меня есть класс .NET, InstrumentConnector, у которого есть событие StatusChanged. Я хочу создать несколько экземпляров этого класса (каждый класс обрабатывает отдельный файл) и отвечать, когда событие StatusChanged вызывается любым экземпляром. Как бы я сделал это в .NET? Хочу ли я создать список (Of InstrumentConnector) или аналогичный IEnumerable? Как написать обработчик события для ответа на событие StatusChanged конкретного экземпляра?

Вот класс InstrumentConnector и модуль с обработчиком StatusChanged:

Public Class InstrumentConnector

Private _inProcessDir As String
Private _doneDir As String

Private _dataFileName As String
Public ReadOnly Property DataFileName() As String
    Get
        Return _dataFileName
    End Get

End Property


Private WithEvents _processTimer As Timers.Timer

Private _fileStatus As Status
Public ReadOnly Property FileStatus() As Status
    Get
        Return _fileStatus
    End Get

End Property


Public Sub New(ByVal inProcessDirectory As String, ByVal doneDirectory As String)
    _inProcessDir = inProcessDirectory
    _doneDir = doneDirectory
    _fileStatus = Status.Waiting
End Sub

Public Sub New(ByVal inProcessDirectory As String)
    Me.New(inProcessDirectory, IO.Path.Combine(inProcessDirectory, "done"))
End Sub

Private Sub InitializeTimer()
    _processTimer = New Timers.Timer
    With _processTimer
        .Interval = 1000
    End With
End Sub

Public Sub Process(ByVal dataFileName As String)

    _dataFileName = IO.Path.GetFileName(dataFileName)

    InitializeTimer()

    _processTimer.Start()

End Sub

Private Sub _processTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _processTimer.Elapsed

    '1. Look for file in Done directory
    '2. Evaluate its approval status
    '3. If not completed change approval setting in file and move to InProcess directory

    If IsFileInProcessDirectory() = True Then
        MoveFileToDoneDirectory()
    Else
        If IsFileInDoneDirectory() = True Then
            If IsFileApproved() = True Then
                _fileStatus = Status.Accepted
                RaiseEvent StatusChanged(Nothing)
            Else
                If NeedsSecondAttempt() = True Then
                    MoveFileToProcessDirectory()
                Else
                    _fileStatus = Status.Rejected
                    RaiseEvent StatusChanged(Nothing)
                End If

            End If

        End If
    End If

End Sub

Private Sub MoveFileToDoneDirectory()

    Dim fileContents As String
    fileContents = My.Computer.FileSystem.ReadAllText(IO.Path.Combine(_inProcessDir, _dataFileName))

    If GetFileApprovalStatus() = True Then
        fileContents = String.Concat("9999", fileContents.Substring(4))
    End If

    My.Computer.FileSystem.WriteAllText(IO.Path.Combine(_doneDir, _dataFileName), fileContents, False)
    My.Computer.FileSystem.DeleteFile(IO.Path.Combine(_inProcessDir, _dataFileName))

End Sub

Private Function NeedsSecondAttempt() As Boolean
    Dim fileContents As String
    fileContents = My.Computer.FileSystem.ReadAllText(IO.Path.Combine(_doneDir, _dataFileName))

    If fileContents.StartsWith("9999") And fileContents.Substring(111, 1) = "1" Then
        Return False
    Else
        Return True
    End If

End Function

Private Sub MoveFileToProcessDirectory()

    Dim fileContents As String
    fileContents = My.Computer.FileSystem.ReadAllText(IO.Path.Combine(_doneDir, _dataFileName))

    fileContents = fileContents.Remove(111, 1).Insert(111, "1")
    My.Computer.FileSystem.WriteAllText(IO.Path.Combine(_doneDir, _dataFileName), fileContents, False)

    My.Computer.FileSystem.MoveFile(IO.Path.Combine(_doneDir, _dataFileName), IO.Path.Combine(_inProcessDir, _dataFileName))

End Sub

Private Function IsFileInDoneDirectory() As Boolean

    Dim fileExists As Boolean
    fileExists = My.Computer.FileSystem.FileExists(IO.Path.Combine(_doneDir, _dataFileName))

    Return fileExists

End Function

Private Function IsFileInProcessDirectory() As Boolean

    Dim fileExists As Boolean
    fileExists = My.Computer.FileSystem.FileExists(IO.Path.Combine(_inProcessDir, _dataFileName))

    Return fileExists

End Function

Private Function IsFileApproved() As Boolean

    Dim fileContents As String
    fileContents = My.Computer.FileSystem.ReadAllText(IO.Path.Combine(_doneDir, _dataFileName))

    If fileContents.Substring(0, 4) = "9999" Then
        Return True
    Else
        Return False
    End If

End Function

Private Function GetFileApprovalStatus() As Boolean

    Dim randNum As New Random
    Dim nextNum = randNum.Next(1, 10)

    '60% of all samples will be approved
    If nextNum > 6 Then
        Return False
    Else
        Return True
    End If

End Function

Public Event StatusChanged(ByVal e As System.EventArgs)

Protected Overridable Sub OnStatusChanged(ByVal e As System.EventArgs) Handles Me.StatusChanged
    _processTimer.Stop()
End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
    _processTimer.Stop()

End Sub

Public Enum Status
    Accepted
    Rejected
    Waiting
End Enum

Конечный класс

Module Module1

Private WithEvents detector As NewFileDetector
Private WithEvents newIC As InstrumentConnector
Private ICList As New List(Of InstrumentConnector)
Private fileDirectory As String

Sub Main()

    fileDirectory = "c:\temp\inproc"

    Console.WriteLine("Mock IC program running...")
    Console.WriteLine()
    Console.WriteLine("Press ESC to quit...")

    detector = New NewFileDetector(fileDirectory)


    Dim keyresponse As ConsoleKeyInfo = Nothing

    Do
        keyresponse = Console.ReadKey

    Loop Until keyresponse.Key = ConsoleKey.Escape 'Quit program on ESC

End Sub

Private Sub detector_FilesFound(ByVal e As System.EventArgs) Handles detector.FilesFound

    Console.WriteLine("Files found: {0}", detector.FileList.Count)

    For Each filename In detector.FileList
        newIC = New InstrumentConnector(fileDirectory)
        ICList.Add(newIC)
        newIC.Process(filename)
    Next

End Sub

Private Sub newIC_StatusChanged(ByVal e As System.EventArgs) Handles newIC.StatusChanged
    Console.WriteLine("File: {0} Status: {1}", newIC.DataFileName, newIC.FileStatus.ToString)
    ICList.Remove(newIC)

End Sub

Конечный модуль

Ответы [ 2 ]

1 голос
/ 24 июня 2011

Немного поздно об этом, но: это именно та проблема, которую решает Microsoft CAB Framework. Это позволяет любому событию иметь нескольких подписчиков и нескольких издателей.

Существует версия этого фреймворка с открытым исходным кодом здесь .

0 голосов
/ 21 января 2011

Способ хранения InstrumentConnectors не связан с событиями.A List(Of T) в порядке.

И вы можете подключить класс слушателя к нескольким источникам событий.Вот почему стандартный шаблон в .NET имеет параметр sender.Просто приведите это к InstrumentConnector, и все готово.

То есть, если StatusChanged разработан в соответствии с правилами.


ОК, возьмите 2.

Сейчас слишком много кода.Трудно пройти.

   Public Event StatusChanged(ByVal e As System.EventArgs)

Не определен правильно.Это должно было быть

   Public Event StatusChanged(ByVal sender as Object,  ByVal e As System.EventArgs)

И мой VB немного заржавел, рядом с нотацией «Ручки» вы должны иметь возможность поместить (где-то)

 HandlesEvent Me.StatusChangedHandler, someInstrument.Statuschanged  ' very sloppy approx

Итогда в классе по вашему выбору (форма может быть)

 Sub StatusChangedHandler(ByVal sender as Object,  ByVal e As System.EventArgs)
    Dim InsConn as InstrumentConnector = sender ' may need a CType() here
    .... 
 End Sub
...