ทํางานกับ Excel ใน .NET โดยไม่ขึ้นกับ Excel เวอร์ชันที่ติดตั้ง
สภาพแวดล้อมในการทํางาน
- วิชวลสตูดิโอ
-
- วิชวลสตูดิโอ 2022
- ตาข่าย
-
- .NET 6.0
- หน้าต่าง
-
- หน้าต่าง 7
- หน้าต่าง 11
- ยอดเยี่ยม
-
- ไมโครซอฟท์ 365
- สํานักงาน 2007
เบื้องต้น
- หน้าต่าง
-
- หนึ่งในรุ่น
- ยอดเยี่ยม
-
- หนึ่งในรุ่น
ปัญหาเกี่ยวกับไลบรารีที่ทํางานกับ Excel
วิธีหนึ่งในการโต้ตอบกับ Excel โดยทางโปรแกรมคือ Microsoft.Office.Interop.Excel
การอ้างอิง
สิ่งนี้คล้ายกับการทํางานโดยตรงกับแอปพลิเคชัน Excel ผ่าน COM ดังนั้นจึงแตกต่างจากการทํางานกับข้อมูลในไฟล์ Excel เล็กน้อย
ตามหลักฐาน Excel จะต้องติดตั้งในสภาพแวดล้อมที่จะดําเนินการ แต่ฟังก์ชันมากมายของ Excel มีให้ใช้งานจากด้านโปรแกรม
Microsoft.Office.Interop.Excel
หากคุณใช้โปรแกรมคุณจะคิดว่าโปรแกรมจะถูกเขียนด้วยวิธีต่อไปนี้
// 実行プログラムの場所にある 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);
}
เป็นเรื่องยากที่จะต้องปล่อยทรัพยากรในแต่ละครั้ง แต่เนื่องจากคุณสามารถใช้คลาสที่เตรียมไว้ได้ คุณจึงสามารถประมวลผล Excel ได้อย่างสังหรณ์ใจ
อย่างไรก็ตามข้อเสียเปรียบคือเวอร์ชันของไลบรารีที่อ้างอิงโดยโปรแกรมจะต้องตรงกันหรือเข้ากันได้กับเวอร์ชันของ Excel ที่ติดตั้งในสภาพแวดล้อมที่กําลังทํางานอยู่ ตัวอย่างเช่น โปรแกรมที่สร้างขึ้นโดยอ้างอิงไลบรารี Excel เวอร์ชัน 15.0 (2013) ภายในสามารถเรียกใช้เมื่อติดตั้ง Excel 2013 เท่านั้น ถ้าคุณต้องการให้โปรแกรมของคุณทํางานในสภาพแวดล้อมต่างๆ คุณอาจต้องให้การติดตั้ง Excel ของคุณทํางานบนเวอร์ชันที่สอดคล้องกัน
หากการดําเนินการดังกล่าวเป็นไปได้ก็ไม่เป็นไร แต่ถ้า Excel เวอร์ชันที่ติดตั้งแตกต่างกันก็ไม่สามารถรองรับได้ ดังนั้นจึงจําเป็นต้องทําอะไรบางอย่างในด้านโปรแกรม
การอ้างอิงไลบรารีแบบไดนามิกด้วยไดนามิกแทนที่จะอ้างอิงโดยตรง
ปัญหาในกรณีนี้เกิดขึ้นเนื่องจากรุ่นของไลบรารีถูกอ้างอิงได้รับการแก้ไขเมื่อโปรแกรมถูกสร้างขึ้น ซึ่งหมายความว่าแทนที่จะกําหนดเวอร์ชันในขณะที่สร้างโปรแกรมจําเป็นต้องกําหนดเวอร์ชันในขณะที่เรียกใช้โปรแกรม
มีหลายวิธีในการทํา แต่คราวนี้เราจะแก้ปัญหาโดยใช้ "" "" และ ""Type.GetTypeFromProgID
Activator.CreateInstance
dynamic
โดยปกติ ใน C# จําเป็นต้องกําหนดข้อมูลประเภท ณ เวลาที่สร้างโปรแกรม แต่ถ้าประเภทคือ dynamic
สามารถกําหนดประเภทได้ในขณะที่ดําเนินการ
object
dynamic
ถ้าอินสแตนซ์ที่ตั้งค่าเป็นตัวแปรเป็นคลาส คุณยังสามารถเรียกเมธอดและคุณสมบัติของคลาสนั้นได้อีกด้วย
อย่างไรก็ตามเนื่องจากสิ่งที่เข้าสู่ตัวแปรจะถูกกําหนดในช่วงเวลาของการดําเนินการข้อผิดพลาดจะเกิดขึ้นในเวลาดําเนินการหากไม่มีวิธีการที่ระบุ
รหัสที่สร้างขึ้นโดยใช้สิ่งเหล่านี้มีดังนี้
// 実行プログラムの場所にある 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);
}
ประเภทของการประกาศตัวแปรคือ dynamic
และ Excel.Application
การสร้างแตกต่างกันเล็กน้อย แต่รหัสที่เหลือจะถูกนํากลับมาใช้ใหม่เกือบทั้งหมด
เนื่องจากโค้ดด้านบนไม่ได้อ้างถึงไลบรารี Excel จึงไม่สามารถใช้ข้อมูลคลาสที่เกี่ยวข้องกับ Excel เป้าหมายได้ ดังนั้นประเภทของตัวแปรคือ ทั้งหมด dynamic
.
นอกจากนี้ เนื่องจากเราไม่สามารถอ้างอิงคลาสได้โดยตรงExcel.Application
เราจึงExcel.Application
Type.GetTypeFromProgID
ได้รับข้อมูลActivator.CreateInstance
ประเภทและส่งต่อไปยังเพื่อสร้างExcel.Application
อินสแตนซ์ของ .
อย่างไรก็ตามในสภาพแวดล้อมที่ไม่ได้ติดตั้ง Type.GetTypeFromProgID
Excel คุณไม่สามารถรับได้ Type
ดังนั้นจึงเป็นไปได้ที่จะแยกได้ว่ามีการติดตั้งหรือไม่
dynamic
ข้อเสียของการใช้คือไม่สามารถกําหนดคลาสได้เมื่อสร้างโปรแกรม
Intellisense ซึ่งเป็นฟังก์ชันเสร็จสิ้นเมื่อป้อนรหัส จะไม่แสดงชื่อเมธอดและชื่อคุณสมบัติ
การเขียนโค้ดโดยอ้างอิงถึงไลบรารีในตอนเริ่มต้นอาจยุ่งยากน้อยกว่าและแทนที่ในภายหลังdynamic
เมื่อทํางานในสภาพแวดล้อม Microsoft 365 คุณสามารถยืนยันได้ว่าจะแสดงดังนี้
ต่อไปนี้เป็นผลมาจากการเรียกใช้บน Office 2007 รุ่นเก่ากว่ามาก หากคุณไม่ได้ใช้ฟังก์ชันที่ใช้งานได้เฉพาะในเวอร์ชันใดเวอร์ชันหนึ่งคุณสามารถทําให้ใช้งานได้อย่างกว้างขวาง
อย่างไรก็ตามหากคุณเรียกใช้ในสภาพแวดล้อมที่ไม่ได้ติดตั้ง Excel คุณสามารถระบุได้อย่างถูกต้องว่าไม่สามารถประมวลผลได้