2015-05-21 1 views
0

Насколько я знаю, в COM Interop, если мы пересекаем границу .NET/COM, мы получаем прирост внутреннего счетчика RCW. Так что я создал книгу VSTO Excel (2013) приложение и побежал код:COM Interop RCW Reference Count для объекта диапазона Excel

private void RCWWorkbooks() 
{ 
Excel.Workbooks wbs = Application.Workbooks;Excel.Workbook book1 = wbs[1]; 
Excel.Workbook book2 = wbs[1]; 
Excel.Workbook book3 = wbs[1]; 
Debug.WriteLine("Book3:= " + Marshal.ReleaseComObject(book3)); 
Debug.WriteLine("Book2:= " + Marshal.ReleaseComObject(book2)); 
Debug.WriteLine("Book1:= " + Marshal.ReleaseComObject(book1)); 
} 

И выход, как я ожидал:

Book3:=2 
Book2:=1 
Book1:=0 

т.е. у нас есть 3 ссылки, общее кол-3 в RCW, который каждый получает уменьшается на 1, когда я призываю ReleaseCOMObject

Я сделал то же самое для испытания рабочего листа: на этот раз я получаю результаты:

private void RCWSheets() 
{ 
Excel.Sheets wks = Application.Workbooks[1].Worksheets; 
Excel.Worksheet sht1 = wks[1]; 
Excel.Worksheet sht2 = wks[1]; 
Excel.Worksheet sht3 = wks[1]; 
Debug.WriteLine("Sheet3:= " + Marshal.ReleaseComObject(sht3)); 
Debug.WriteLine("Sheet2:= " + Marshal.ReleaseComObject(sht2)); 
Debug.WriteLine("Sheet1:= " + Marshal.ReleaseComObject(sht1)); 
} 

И результат был не таким, каким я ожидал.

Sheet3:=3 
Sheet2:=2 
Sheet1:=1 

Не могу решить, почему sheet3: = 3. Я ожидал, что это будет 2.

Далее я попробовал тест диапазона с помощью следующего кода:

private void RCWRanges() 
{ 
Excel.Worksheet sht = Application.Workbooks[1].Worksheets[1]; 
Excel.Range r1 = sht.Range["A1"]; 
Excel.Range r2 = sht.Range["A1"]; 
Excel.Range r3 = sht.Range["A1"]; 
Debug.WriteLine("Range3:= " + Marshal.ReleaseComObject(r3)); 
Debug.WriteLine("Range2:= " + Marshal.ReleaseComObject(r2)); 
Debug.WriteLine("Range1:= " + Marshal.ReleaseComObject(r1)); 
} 

Опять же, выход не было, как я ожидал:

Range3:=0 
Range2:=0 
Range1:=0 

Так что мой вопросы:

  1. Почему листовой тест вернул дополнительный счет. Он вернулся 3, где я ожидал двух.
  2. Почему тест диапазона возвращал 0 для всех отсчетов ссылок? Это говорит о том, что запрос диапазона не пересекает барьер .NET/COM.

Благодаря

+1

Довольно хороший пример, почему ручное управление памятью является такой ошибкой. Объектная модель автоматизации Excel слишком сложна, чтобы получить право на это. Обратите внимание на свойство ActiveSheet в объекте Application, которое также может иметь ссылку на первый лист. Workbook и WorkSheet являются дорогостоящими объектами, Excel избегает создания дополнительных экземпляров. Диапазоны нет. Не пишите такой код, вы всегда будете ошибаться. Сборщик мусора никогда не делает. –

+0

Спасибо, Ханс. Могу я просто спросить, знаете ли вы какую-либо документацию в любом месте, где объясняется бит Range, о чем вы говорили. Я ничего не могу найти по этому поводу. то есть, как вы знаете, что объекты диапазона обрабатываются таким образом. – PaulG

+0

Нет такой документации. Единственная причина, по которой я знаю, это то, что вы только что сказали мне. –

ответ

0

После немного отладки ...

прокси вернулся и используется в управляемом коде для объекта рабочего листа сохраняется между вызовами функций для всего домена приложения. Например, предположим, что у вас есть два метода, называемые последовательно Method1 и Method2, и каждый метод устанавливает ссылку на объект рабочей таблицы. Первый метод создаст прокси для рабочего листа. Второй вызов будет использовать один и тот же прокси для другой ссылки на другой объект листа. Таким образом, число RCW теперь два.

Однако для объекта диапазона этот же прокси-сервер, похоже, не имеет места. Похоже, что для разных ссылок диапазона создается отдельный прокси-сервер. Это можно увидеть, если вы используете тест:

Excel.Range r1 = sht1.Range["A1"]; 
Excel.Range r2 = sht1.Range["A1"]; 
Debug.WriteLine("r1=r2: " + ReferenceEquals(r1,r2)); 

Это возвращает False. Это объясняет, почему в исходном вопросе подсчеты отображались как ноль.

Что касается очистки объекта, я считаю, что лучший способ сделать это - сочетание вещей. Наличие собственного домена приложения для вызовов interop означает, что все ссылки будут рассмотрены правильно, что VSTO делает. В качестве альтернативы используйте прокладку. Существует также возможность при определенных обстоятельствах, когда оставлять это в сборщике габарей полностью не может, что вам нужно - например, у вас может быть много больших объектов, которые вы хотите освободить сейчас, а не ждать. В этом случае я считаю, что исправление вручную. Там также вручную вызывается мусор. Но я лично думаю, что есть разные ситуации, когда звонить.

0

если мы пересекаем границу .NET/COM мы получаем приращение внутреннего счетчика RCW.

Вы находитесь на неправильном проспекте. В RCW нет счетчиков. Счетчик находится в COM-объекте, а не RCW. RCW - управляемое представление COM-объекта, который перенаправляет ваши вызовы на неуправляемый код.

Почему листовой тест вернул дополнительный счет. Он вернулся 3, где я ожидал двух.

Могут быть любые другие надстройки, которые могут использовать один и тот же объект (а не только). Таким образом, вызов метода FinalReleaseComObject в таких случаях может привести к поломке приложения и вызвать исключения, возникающие во время выполнения.

Почему тест диапазона возвращал 0 для всех отсчетов ссылок? Это говорит о том, что запрос диапазона не пересекает барьер .NET/COM.

Кажется, что новый COM-объект создается в соответствии с переданным параметром указателю.Попробуйте передать разные значения - A1, B1, C1. Полагаю, вы получите ту же картину.

+0

(1). Вы в этом уверены? https://limbioliong.wordpress.com/2011/08/09/rcw-internal-reference-count/ ... посмотрите на пункт 4.3 на этой странице. (2). Это обычная процедура, никто другой ничего не делает. Тем не менее, не объясняет, почему его 3. – PaulG

+0

В статье говорится: RCW внутренне поддерживает ** отдельный ** счетчик ссылок. –