NET'te Excel ile Excel'in yüklü sürümünden bağımsız olarak çalışın

Sayfa güncel :
Sayfa oluşturma tarihi :

Çalışma ortamı

Visual Studio
  • Visual Studio 2022
.NET
  • .NET 6.0
Windows
  • pencereler 7
  • pencereler 11
Excel
  • Microsoft 365 (İngilizce)
  • Ofis 2007

Önkoşullar

Windows
  • Sürümlerden biri
Excel
  • Sürümlerden biri

Excel ile çalışan kitaplıklarla ilgili sorunlar

Excel ile programlı olarak etkileşim kurmanın bir yolu, Microsoft.Office.Interop.Excel . Bu, COM aracılığıyla doğrudan Excel uygulamasıyla çalışmaya benzer, bu nedenle bir Excel dosyasındaki verilerle çalışmaktan biraz farklıdır. Öncül olarak, yürütülecek ortamda Excel'in kurulu olması gerekir, ancak Excel'in birçok işlevi program tarafında kullanılabilir.

Microsoft.Office.Interop.Excel Programı kullanırsanız programın aşağıdaki şekilde yazılacağını düşünürsünüz.

// 実行プログラムの場所にある Excel ファイル
var excelFilePath = $@"{Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)}\Sample.xlsx";

// Excel のオブジェクトは参照したら必ず解放する必要があります。
// 解放しないと Excel のプロセスが残り続けます。
Microsoft.Office.Interop.Excel.Application? excel = null;
Microsoft.Office.Interop.Excel.Workbooks? books = null;
Microsoft.Office.Interop.Excel.Workbook? book = null;
Microsoft.Office.Interop.Excel.Sheets? sheets = null;
Microsoft.Office.Interop.Excel.Worksheet? sheet = null;
Microsoft.Office.Interop.Excel.Range? cells = null;
Microsoft.Office.Interop.Excel.Range? range1 = null;
Microsoft.Office.Interop.Excel.Range? range2 = null;
try
{
  // Excel アプリケーションを生成(起動)します
  excel = new Microsoft.Office.Interop.Excel.Application
  {
    DisplayAlerts = false
  };

  // ワークブック一覧を参照します。参照する場合は必ず変数に保持します
  books = excel.Workbooks;

  // Excel ファイルを開きます
  book = books.Open(excelFilePath);

  // シート一覧を参照するので変数に保持します
  sheets = book.Worksheets;

  // シートを参照します。最初のシートは 1 になります
  sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets[1];

  // セル一覧を参照します
  cells = sheet.Cells;

  // 左上のセルを参照します。一番左上は [1, 1] になります
  range1 = (Microsoft.Office.Interop.Excel.Range)cells[1, 1];

  // セルの値を取得します。値の取得なので後で解放する必要はありません
  var value = (int)range1.Value;

  // 下のセルを参照します
  range2 = (Microsoft.Office.Interop.Excel.Range)cells[2, 1];

  // 日付分足してセットします
  range2.Value = DateTime.Now.Day + value;

  // 保存して閉じます
  book.Close(SaveChanges: true);

  Console.WriteLine("処理が完了しました。");
}
catch (Exception ex)
{
  // 閉じていなければ保存せずに閉じます
  // 開きっぱなしだと Excel 起動時に保存されていないデータとして表示される場合があります
  if (book != null) book.Close(SaveChanges: false);

  Console.WriteLine("処理が失敗しました。");
  Console.WriteLine(ex);
}
finally
{
  // 終了していなければ終了します
  if (excel != null) excel.Quit();

  // 例外が発生した場合でも必ずリソースを解放するようにします
  if (range1 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range1);
  if (range2 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range2);
  if (cells != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cells);
  if (sheet != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
  if (sheets != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets);
  if (book != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
  if (books != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(books);
  if (excel != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}

Her seferinde kaynakları serbest bırakmak zorunda kalmak zahmetlidir, ancak hazırlanan sınıfları kullanabildiğiniz için Excel işlemeyi nispeten sezgisel olarak gerçekleştirebilirsiniz.

Ancak dezavantajı, program tarafından başvurulan kitaplığın sürümünün, çalıştığı ortamda yüklü olan Excel sürümüyle eşleşmesi veya uyumlu olması gerektiğidir. Örneğin, Excel'in dahili sürüm 15.0 (2013) kitaplığına başvurularak oluşturulan bir program yalnızca Excel 2013 yüklendiğinde çalışabilir. Programınızın birçok ortamda çalışmasını istiyorsanız, Excel yüklemenizi tutarlı bir sürümde çalışır durumda tutmanız gerekebilir.

Böyle bir işlem mümkünse, sorun değil, ancak Excel'in yüklü sürümü farklıysa, yerleştirilemez. Bu nedenle, program tarafında bir şeyler yapmak gerekir.

Kitaplıklara doğrudan başvurmak yerine dinamik olarak başvurmak

Bu durumda sorun, program oluşturulduğunda kitaplık sürümüne başvurulduğu için oluşur. Bu, program oluşturma sırasındaki sürümü belirlemek yerine, programın yürütülmesi sırasındaki sürümü belirlemenin gerekli olduğu anlamına gelir.

Bunu yapmanın birkaç yolu var, ancak bu sefer "" "" ve ""Type.GetTypeFromProgIDActivator.CreateInstance kullanarak çözeceğiz.dynamic

Normalde, C#'da, program oluşturma sırasında tür bilgisini belirlemek gerekir, ancak tür ise, tür dynamic yürütme sırasında belirlenebilir. object Türlerden farklı olarak dynamic , bir değişkene ayarlanan örnek bir sınıfsa, o sınıfın yöntemlerini ve özelliklerini de çağırabilirsiniz. Ancak, değişkene ne gireceği yürütme zamanlamasında belirlendiğinden, belirli bir yöntem yoksa yürütme sırasında bir hata oluşacaktır.

Bunlar kullanılarak oluşturulan kod aşağıdaki gibidir.

// 実行プログラムの場所にある Excel ファイル
var excelFilePath = $@"{Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName)}\Sample.xlsx";

// Excel のオブジェクトは参照したら必ず解放する必要があります。
// 解放しないと Excel のプロセスが残り続けます。
dynamic? excel = null;
dynamic? books = null;
dynamic? book = null;
dynamic? sheets = null;
dynamic? sheet = null;
dynamic? cells = null;
dynamic? range1 = null;
dynamic? range2 = null;
try
{
  // Excel.Application の Type を取得
  var type = Type.GetTypeFromProgID("Excel.Application");
  if (type == null)
  {
    Console.WriteLine("Excel がインストールされていません。");
    return;
  }

  // Excel アプリケーションを生成(起動)します
  excel = Activator.CreateInstance(type);
  if (excel == null)
  {
    Console.WriteLine("Excel.Application のインスタンスの生成に失敗しました。");
    return;
  }
  excel.DisplayAlerts = false;

  // ワークブック一覧を参照します。参照する場合は必ず変数に保持します
  books = excel.Workbooks;

  // Excel ファイルを開きます
  book = books.Open(excelFilePath);

  // シート一覧を参照するので変数に保持します
  sheets = book.Worksheets;

  // シートを参照します。最初のシートは 1 になります
  sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets[1];

  // セル一覧を参照します
  cells = sheet.Cells;

  // 左上のセルを参照します。一番左上は [1, 1] になります
  range1 = (Microsoft.Office.Interop.Excel.Range)cells[1, 1];

  // セルの値を取得します。値の取得なので後で解放する必要はありません
  var value = (int)range1.Value;

  // 下のセルを参照します
  range2 = (Microsoft.Office.Interop.Excel.Range)cells[2, 1];

  // 日付分足してセットします
  range2.Value = DateTime.Now.Day + value;

  // 保存して閉じます
  book.Close(SaveChanges: true);

  Console.WriteLine("処理が完了しました。");
}
catch (Exception ex)
{
  // 閉じていなければ保存せずに閉じます
  // 開きっぱなしだと Excel 起動時に保存されていないデータとして表示される場合があります
  if (book != null) book.Close(SaveChanges: false);

  Console.WriteLine("処理が失敗しました。");
  Console.WriteLine(ex);
}
finally
{
  // 終了していなければ終了します
  if (excel != null) excel.Quit();

  // 例外が発生した場合でも必ずリソースを解放するようにします
  if (range1 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range1);
  if (range2 != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(range2);
  if (cells != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(cells);
  if (sheet != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheet);
  if (sheets != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sheets);
  if (book != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(book);
  if (books != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(books);
  if (excel != null) System.Runtime.InteropServices.Marshal.FinalReleaseComObject(excel);
}

Değişkenin bildiriminin türü 'dir dynamic ve Excel.Application oluşturulması biraz farklıdır, ancak kodun geri kalanı neredeyse yeniden kullanılır.

Yukarıdaki kod Excel kitaplığına başvurmadığından, Excel ile ilgili hedef sınıf bilgilerini kullanmak mümkün değildir. Bu nedenle, değişkenin türü all dynamic şeklindedir. Ayrıca, sınıfa doğrudan başvuramadığımız için,Excel.Application bunun yerine Excel.Application Type.GetTypeFromProgID Type bilgisini Activator.CreateInstance alır ve bir örneğini oluşturmak Excel.Application için 'a iletiriz. Bu arada, Excel'in kurulu olmadığı bir ortamda, onu Type alamazsınız , Type.GetTypeFromProgID bu nedenle kurulu olup olmadığını izole etmek mümkündür.

dynamic Kullanmanın dezavantajı, program oluşturulurken sınıfın belirlenememesidir. Kod girerken bir tamamlama işlevi olan Intellisense, yöntem adlarını ve özellik adlarını görüntülemez. Başlangıçta kitaplığa başvurarak kod yazmak ve daha sonra ile dynamic değiştirmek daha az zahmetli olabilir.

Microsoft 365 ortamında çalışırken, aşağıdaki gibi yansıtıldığını onaylayabilirsiniz.

Aşağıdakiler, Office 2007'nin çok daha eski bir sürümünde çalıştırmanın sonucudur. Yalnızca belirli bir sürümde çalışan bir işlev kullanmazsanız, oldukça yaygın bir şekilde çalışmasını sağlayabilirsiniz.

Bu arada, Excel'in yüklü olmadığı bir ortamda çalıştırırsanız, işlenemeyeceğini doğru bir şekilde belirleyebilirsiniz.