Domanda

Ho un'applicazione Windows Workflow che utilizza le classi che ho scritto per l'automazione COM.Sto aprendo Word ed Excel dalle mie lezioni utilizzando COM.

Attualmente sto implementando IDisposable nel mio helper COM e utilizzo Marshal.ReleaseComObject().Tuttavia, se il flusso di lavoro fallisce, il metodo Dispose() non viene chiamato e gli handle di Word o Excel rimangono aperti e l'applicazione si blocca.

La soluzione a questo problema è piuttosto semplice, ma piuttosto che risolverlo semplicemente, mi piacerebbe imparare qualcosa e acquisire informazioni sul modo giusto di lavorare con COM.Sto cercando il modo "migliore" o più efficiente e sicuro per gestire il ciclo di vita delle classi che possiedono gli handle COM.Sarebbero utili modelli, best practice o codice di esempio.

È stato utile?

Soluzione

Non riesco a vedere quale errore hai che non chiama il metodo Dispose().Ho effettuato un test con un flusso di lavoro sequenziale che contiene solo un'attività di codice che genera semplicemente un'eccezione e il metodo Dispose() del mio flusso di lavoro viene chiamato due volte (questo è dovuto al gestore di eventi WorkflowTermination standard).Controlla il seguente codice:

Program.cs

    class Program
    {
        static void Main(string[] args)
        {
            using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
            {
                AutoResetEvent waitHandle = new AutoResetEvent(false);
                workflowRuntime.WorkflowCompleted += delegate(object sender, WorkflowCompletedEventArgs e) 
                {
                    waitHandle.Set();
                };
                workflowRuntime.WorkflowTerminated += delegate(object sender, WorkflowTerminatedEventArgs e)
                {
                    Console.WriteLine(e.Exception.Message);
                    waitHandle.Set();
                };

                WorkflowInstance instance = workflowRuntime.CreateWorkflow(typeof(WorkflowConsoleApplication1.Workflow1));
                instance.Start();

                waitHandle.WaitOne();
            }
            Console.ReadKey();
        }
    }

Workflow1.cs

    public sealed partial class Workflow1: SequentialWorkflowActivity
    {
        public Workflow1()
        {
            InitializeComponent();
            this.codeActivity1.ExecuteCode += new System.EventHandler(this.codeActivity1_ExecuteCode);
        }

        [DebuggerStepThrough()]
        private void codeActivity1_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("Throw ApplicationException.");
            throw new ApplicationException();
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // Here you must free your resources 
                // by calling your COM helper Dispose() method
                Console.WriteLine("Object disposed.");
            }
        }
    }

Mi sto perdendo qualcosa?Per quanto riguarda i metodi relativi al ciclo di vita di un oggetto Activity (e di conseguenza di un Workflow), consulta questo post: Metodi di attività "a vita"..Se desideri solo un articolo generico sullo smaltimento, controlla Questo.

Altri suggerimenti

Fondamentalmente, non dovresti fare affidamento sul codice manuale per chiamare Dispose() sul tuo oggetto alla fine del lavoro.Probabilmente hai qualcosa del genere in questo momento:

MyComHelper helper = new MyComHelper();
helper.DoStuffWithExcel();
helper.Dispose();
...

È invece necessario utilizzare i blocchi try per rilevare qualsiasi eccezione che potrebbe essere attivata e a quel punto chiamare Dispose.Questo è il modo canonico:

MyComHelper helper = new MyComHelper();
try
{
    helper.DoStuffWithExcel();
}
finally()
{
    helper.Dispose();
}

Questo è COSÌ comune che C# abbia un costrutto speciale che genera lo stesso identico codice [Vedi nota] come mostrato sopra;questo è ciò che dovresti fare la maggior parte del tempo (a meno che tu non abbia una semantica speciale per la costruzione di oggetti che renda più facile lavorare con un modello manuale come quello sopra):

using(MyComHelper helper = new MyComHelper())
{
    helper.DoStuffWithExcel();
}

MODIFICARE:
NOTA:Il codice effettivamente generato è leggermente più complicato del secondo esempio sopra, perché introduce anche un nuovo ambito locale che rende l'oggetto helper non disponibile dopo il using bloccare.È come se il secondo blocco di codice fosse circondato da { }.Questo è stato omesso per chiarire la spiegazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top