การปิดกระบวนการสมัคร Excel ใน C # หลังการเข้าถึงข้อมูล


88

ฉันกำลังเขียนแอปพลิเคชันใน C # ที่เปิดไฟล์เทมเพลต Excel สำหรับการอ่าน / เขียน ฉันต้องการให้เมื่อผู้ใช้ปิดแอปพลิเคชันขั้นตอนการสมัคร excel ถูกปิดโดยไม่บันทึกไฟล์ excel ดูตัวจัดการงานของฉันหลังจากเรียกใช้แอพหลายครั้ง

ป้อนคำอธิบายภาพที่นี่

ฉันใช้รหัสนี้เพื่อเปิดไฟล์ excel:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");

และสำหรับการเข้าถึงข้อมูลฉันใช้รหัสนี้:

Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

ฉันเห็นคำถามที่คล้ายกันใน stackoverflow เช่นคำถามนี้และคำถามนี้และคำตอบทดสอบ แต่ไม่ได้ผล


Excel และ Word ทำงานช้ามากและมาพร้อมกับความแปลกประหลาดมากมายเช่นเดียวกับที่คุณเคยสะดุด ไฟล์เหล่านี้เป็นไฟล์ zip ที่มี XML และเนื้อหาอื่น ๆ อยู่ในนั้น นอกจากนี้ยังมี Open XML SDK (หรืออาจจะเป็นรุ่นล่าสุด) ที่สามารถเปิดเอกสารได้ รหัสดังกล่าวทำงานได้โดยไม่ต้องติดตั้ง Office ในเครื่องด้วย อย่าใช้ Excel
Sten Petrov

คำตอบ:


97

ลองสิ่งนี้:

excelBook.Close(0); 
excelApp.Quit();

เมื่อปิดสมุดงานคุณมีพารามิเตอร์ทางเลือกสามตัว:

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)หรือหากคุณกำลังทำการเชื่อมต่อล่าช้าบางครั้งก็ง่ายกว่าที่จะใช้ศูนย์ Workbook.Close(0) นั่นคือวิธีที่ฉันได้ทำเมื่อปิดสมุดงานโดยอัตโนมัติ

นอกจากนี้ฉันยังไปดูเอกสารและพบที่นี่: Excel Workbook Close

ขอบคุณ


ขอบคุณไมเคิลที่รักมันทำงานได้อย่างถูกต้อง: excelBook.Close (0)
Javad Yousefi

สวัสดีพวกมันไม่ทำงานเมื่อคุณเปิดไฟล์ excel เพื่ออ่าน ต่อไปนี้คือรหัส var excelApp = แอปพลิเคชันใหม่ (); var workBooks = excelApp.Workbooks.Open @ "c: \ temp \ myexcel.xlsx"); สมุดงานปิด (0); excelApp.Quit ();
user1131926

ฉันใช้ applicationClass ... และฉันใช้รหัสด้านบนเพื่อกำจัดวัตถุ แต่มันไม่ได้ผล ...
Singaravelan

3
หลังจากความพยายามที่ล้มเหลวหลายครั้งกับคำตอบทั้งหมดนี้ฉันใช้วิธีแก้ปัญหานี้เพื่อรับรหัสกระบวนการที่ฉันเปิดและฆ่ามันโดยตรง
UndeadBob

@ Singaravelan: คุณตรวจคำตอบของ David Clarke แล้วหรือยัง?
The Anh Nguyen

22
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

ลองดูสิ .. มันได้ผลสำหรับฉัน ... คุณควรปล่อยแอปพลิเคชัน xl นั้นเพื่อหยุดกระบวนการ


14

อ้างอิง: https://stackoverflow.com/a/17367570/132599

หลีกเลี่ยงการใช้นิพจน์การเรียกจุดสองจุดเช่นนี้:

var workbook = excel.Workbooks.Open(/*params*/)

... เพราะด้วยวิธีนี้คุณสร้างอ็อบเจ็กต์ RCW ไม่เพียง แต่สำหรับเวิร์กบุ๊กเท่านั้น แต่สำหรับเวิร์กบุ๊กด้วยและคุณควรปล่อยมันด้วย (ซึ่งเป็นไปไม่ได้หากไม่มีการอ้างอิงถึงอ็อบเจ็กต์)

สิ่งนี้ช่วยแก้ปัญหาให้ฉันได้ รหัสของคุณกลายเป็น:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbooks workbooks;
public Excel.Workbook excelBook;
workbooks = excelApp.Workbooks;
excelBook = workbooks.Add(@"C:/pape.xltx");

...

Excel.Sheets sheets = excelBook.Worksheets;
Excel.Worksheet excelSheet = (Worksheet)(sheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

จากนั้นปล่อยวัตถุเหล่านั้นทั้งหมด:

System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
excelBook .Save();
excelBook .Close(true);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

ฉันห่อสิ่งนี้ไว้try {} finally {}เพื่อให้แน่ใจว่าทุกอย่างจะได้รับการปลดปล่อยแม้ว่าจะมีบางอย่างผิดพลาด (อาจมีอะไรผิดพลาด) เช่น

public Excel.Application excelApp = null;
public Excel.Workbooks workbooks = null;
...
try
{
    excelApp = new Excel.Application();
    workbooks = excelApp.Workbooks;
    ...
}
finally
{
    ...
    if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
    excelApp.Quit();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}

2
สิ่งนี้ได้ผลสำหรับฉันโดยกำหนดเวิร์กบุ๊กให้กับตัวแปรเพื่อให้สามารถล้างข้อมูลได้ นอกจากนี้ข้อสังเกตประการหนึ่งฉันมีรหัสเดียวกันสำหรับการล้างแอป excel ในแอปพลิเคชันเว็บและแอปพลิเคชันคอนโซล รหัสก่อนการอัปเดตการกำจัดจุดคู่ทำงานได้ดีในแอปคอนโซล แต่เมื่อเรียกใช้ในเว็บแอปไม่ได้ล้าง EXCEL.EXE ฉันไม่แน่ใจว่าทำไมพวกเขาถึงทำงานแตกต่างกัน แต่การกำจัดการอ้างอิงจุดสองจุดที่แก้ไขในเว็บแอป
IronHide

ทำงานให้ฉัน ฉันคิดว่าเพื่อปลดปล่อยวัตถุเราต้องปล่อยวัตถุที่เกี่ยวข้องทั้งหมด ฉันมีปัญหาเดียวกันเกี่ยวกับโปรแกรม solidworks
Gs.

1
ปิดเวิร์กบุ๊กออกจากแอปพลิเคชัน Excel หลีกเลี่ยงการโทรแบบจุดสองจุดและปล่อยวัตถุ COM เดียวที่สร้าง ที่ได้ผลสำหรับฉัน คำตอบช่วยชีวิต. ขอบคุณ.
Sinan ILYAS

13

คิดอย่างนี้มันฆ่ากระบวนการ:

System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
    if (!string.IsNullOrEmpty(p.ProcessName))
    {
        try
        {
            p.Kill();
        }
        catch { }
    }
}

นอกจากนี้คุณลองปิดมันตามปกติหรือไม่?

myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
excelBook.Close(null, null, null);                 // close your workbook
excelApp.Quit();                                   // exit excel application
excel = null;                                      // set to NULL

ขอบคุณสำหรับคำตอบโซลูชันแรกของคุณปิดไฟล์ Excel ที่เปิดอยู่ทั้งหมดเมื่อฉันใช้ 'excelBook.Close' กล่องโต้ตอบบันทึก excel จะปรากฏขึ้นและฉันไม่ต้องการ :(
Javad Yousefi

1
ฉันแก้ไขมันและเพิ่มด้วยบรรทัดเพื่อทำ saveAs ในโค้ดซึ่งจะแทนที่กล่องโต้ตอบด้วยรหัสหวังว่าจะช่วยได้ :)
Morris Miao

1
ฉันเพิ่งใช้สิ่งนี้กับการตรวจสอบเบื้องต้นสำหรับกระบวนการ Excel ที่เปิดอยู่และบันทึกรหัสในรายการ จากนั้นทำกระบวนการ Excel ใหม่ทำการแก้ไขที่ฉันต้องทำและปิดกระบวนการ Excel ใด ๆ ที่ไม่มีอยู่ในรายการ ID
182764125216

ไม่ใช่วิธีที่ถูกต้องในการปล่อย excel จากตัวจัดการงาน คุณควรปล่อยวัตถุทั้งหมดที่สร้างขึ้นรวมทั้งวัตถุที่สร้างขึ้นหลังฉากเช่น WorkBOoks
เอ๊ะ

ด้วยวิธีนี้คุณจะฆ่าทุกกระบวนการ Excel ที่กำลังทำงานอยู่ ปัญหาคืออาจมีผู้ใช้หรือแอปพลิเคชันอื่น ๆ ที่ใช้ Excel ในเวลาเดียวกัน โปรดทราบว่าคุณเต็มใจที่จะทำสิ่งนี้หรือไม่
Sinan ILYAS

6

การฆ่า Excel ไม่ใช่เรื่องง่ายเสมอไป ดูบทความนี้: 50 วิธีในการฆ่า Excel

บทความนี้ใช้คำแนะนำที่ดีที่สุดจาก Microsoft ( MS Knowlege Base Article ) เกี่ยวกับวิธีทำให้ Excel เลิกใช้งานได้อย่างดี แต่จากนั้นก็ตรวจสอบให้แน่ใจด้วยการฆ่ากระบวนการหากจำเป็น ฉันชอบมีร่มชูชีพครั้งที่สอง

ตรวจสอบให้แน่ใจว่าได้ปิดสมุดงานที่เปิดอยู่ออกจากแอปพลิเคชันและปล่อยวัตถุ xlApp สุดท้ายตรวจสอบเพื่อดูว่ากระบวนการยังคงมีชีวิตอยู่หรือไม่และถ้าเป็นเช่นนั้นให้ฆ่ามัน

บทความนี้ยังช่วยให้แน่ใจว่าเราไม่ได้ฆ่ากระบวนการ Excel ทั้งหมด แต่จะฆ่าเฉพาะกระบวนการที่เริ่มต้นเท่านั้น

โปรดดูที่รับกระบวนการจาก Window Handle

นี่คือรหัสที่ฉันใช้: (ใช้ได้ทุกครั้ง)

Sub UsingExcel()

    'declare process; will be used later to attach the Excel process
    Dim XLProc As Process

    'call the sub that will do some work with Excel
    'calling Excel in a separate routine will ensure that it is 
    'out of scope when calling GC.Collect
    'this works better especially in debug mode
    DoOfficeWork(XLProc)

    'Do garbage collection to release the COM pointers
    'http://support.microsoft.com/kb/317109
    GC.Collect()
    GC.WaitForPendingFinalizers()

    'I prefer to have two parachutes when dealing with the Excel process
    'this is the last answer if garbage collection were to fail
    If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
        XLProc.Kill()
    End If

End Sub

'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
    ByRef lpdwProcessId As Integer) As Integer
End Function

Private Sub ExcelWork(ByRef XLProc As Process)

    'start the application using late binding
    Dim xlApp As Object = CreateObject("Excel.Application")

    'or use early binding
    'Dim xlApp As Microsoft.Office.Interop.Excel

    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd

    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0

    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)

    'get the process
    XLProc = Process.GetProcessById(ProcIdXL)


    'do some work with Excel here using xlApp

    'be sure to save and close all workbooks when done

    'release all objects used (except xlApp) using NAR(x)


    'Quit Excel 
    xlApp.quit()

    'Release
    NAR(xlApp)

End Sub

Private Sub NAR(ByVal o As Object)
    'http://support.microsoft.com/kb/317109
    Try
        While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
        End While
    Catch
    Finally
        o = Nothing
    End Try
End Sub

นี่เป็นทางออกเดียวที่ใช้ได้ผลสำหรับฉัน ขอบคุณ.
Jon Vote

2

ฉันพบปัญหาเดียวกันและลองหลายวิธีเพื่อแก้ปัญหา แต่ไม่ได้ผล ในที่สุดฉันก็พบทางของฉัน ข้อมูลอ้างอิงบางส่วนป้อนคำอธิบายลิงก์ที่นี่

หวังว่ารหัสของฉันจะช่วยใครบางคนในอนาคต ฉันใช้เวลามากกว่าสองวันในการแก้ปัญหานี้ ด้านล่างนี้คือรหัสของฉัน:

//get current in useing excel
            Process[] excelProcsOld = Process.GetProcessesByName("EXCEL");
            Excel.Application myExcelApp = null;
            Excel.Workbooks excelWorkbookTemplate = null;
            Excel.Workbook excelWorkbook = null;
try{
    //DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook
}
catch (Exception ex ){
}
finally
            {
                //Compare the EXCEL ID and Kill it 
                Process[] excelProcsNew = Process.GetProcessesByName("EXCEL");
                foreach (Process procNew in excelProcsNew)
                {
                    int exist = 0;
                    foreach (Process procOld in excelProcsOld)
                    {
                        if (procNew.Id == procOld.Id)
                        {
                            exist++;
                        }
                    }
                    if (exist == 0)
                    {
                        procNew.Kill();
                    }        
                }
            }

1

excelBook.Close (); excelApp.Quit (); เพิ่มส่วนท้ายของโค้ดก็เพียงพอแล้ว มันทำงานกับรหัสของฉัน


ใช่ แต่เมื่อฉันใช้มันกล่องโต้ตอบบันทึกจะปรากฏขึ้นและฉันไม่ต้องการให้ปรากฏ :(
Javad Yousefi

1

คุณสามารถฆ่ากระบวนการด้วยCOMวัตถุของคุณเองexcel pid

เพิ่มที่ด้านล่างรหัสนำเข้า dll

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);

และใช้

 if (excelApp != null)
            {
                int excelProcessId = -1;
                GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);

                Process ExcelProc = Process.GetProcessById(excelProcessId);
                if (ExcelProc != null)
                {
                    ExcelProc.Kill();
                }
            }

1

ฉันได้พบว่ามันเป็นสิ่งสำคัญที่จะมีMarshal.ReleaseComObjectภายในWhileห่วงและจบด้วยการเก็บขยะ

static void Main(string[] args)
{
    Excel.Application xApp = new Excel.Application();
    Excel.Workbooks xWbs = xApp.Workbooks;
    Excel.Workbook xWb = xWbs.Open("file.xlsx");

    Console.WriteLine(xWb.Sheets.Count);

    xWb.Close();
    xApp.Quit();

    while (Marshal.ReleaseComObject(xWb) != 0);
    while (Marshal.ReleaseComObject(xWbs) != 0);
    while (Marshal.ReleaseComObject(xApp) != 0);

    GC.Collect();
    GC.WaitForPendingFinalizers();
}

0
         wb.Close();
         app.Quit();

         System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
         foreach (System.Diagnostics.Process p in process)
         {
             if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now)
             {
                 try
                 {
                     p.Kill();
                 }
                 catch { }
             }
         }

ปิดกระบวนการ 10 วินาทีสุดท้ายด้วยชื่อ "Excel"


0

ขึ้นอยู่กับโซลูชันอื่น ฉันใช้สิ่งนี้:

IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd);
excelObj.ActiveWorkbook.Close();

System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
                foreach (System.Diagnostics.Process p in process)
                {
                    if (p.MainWindowHandle == xAsIntPtr)
                    {
                        try
                        {
                            p.Kill();
                        }
                        catch { }
                    }
                }

ใช้ "MainWindowHandle" เพื่อระบุกระบวนการและปิดเขา

excelObj: นี่คือ Application Interop excel objecto ของฉัน


0

ใช้ตัวแปรสำหรับแต่ละ Excel Marshal.ReleaseComObject >0วัตถุและต้องห่วง หากไม่มีการวนซ้ำกระบวนการ Excel จะยังคงทำงานอยู่

public class test{
        private dynamic ExcelObject;
        protected dynamic ExcelBook;
        protected dynamic ExcelBooks;
        protected dynamic ExcelSheet;

public void LoadExcel(string FileName)
        {
            Type t = Type.GetTypeFromProgID("Excel.Application");
            if (t == null) throw new Exception("Excel non installato");
            ExcelObject = System.Activator.CreateInstance(t);
            ExcelObject.Visible = false;
            ExcelObject.DisplayAlerts = false;
            ExcelObject.AskToUpdateLinks = false;
            ExcelBooks = ExcelObject.Workbooks;
            ExcelBook = ExcelBooks.Open(FileName,0,true);
            System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
            ExcelSheet = ExcelBook.Sheets[1];
        }
 private void ReleaseObj(object obj)
        {
            try
            {
                int i = 0;
             while(   System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0)
                {
                    i++;
                    if (i > 1000) break;
                }
                obj = null;
            }
            catch 
            {
                obj = null;
            }
            finally
            {
                GC.Collect();
            }
        }
        public void ChiudiExcel() {
            System.Threading.Thread.CurrentThread.CurrentCulture = ci;

            ReleaseObj(ExcelSheet);
            try { ExcelBook.Close(); } catch { }
            try { ExcelBooks.Close(); } catch { }
            ReleaseObj(ExcelBooks);
            try { ExcelObject.Quit(); } catch { }
            ReleaseObj(ExcelObject);
        }
}

0

เราสามารถปิดแอปพลิเคชัน Excel ในขณะที่แปลง xls เป็น xlsx โดยใช้รหัสต่อไปนี้ เมื่อเราทำงานประเภทนี้แสดงว่าแอปพลิเคชัน Excel กำลังทำงานในตัวจัดการงานเราควรปิด excel นี้ซึ่งทำงานอยู่เบื้องหลัง Interop เป็นคอมโพเนนต์ Com เพื่อปล่อยคอมโพเนนต์ com ที่เราใช้ Marshal.FinalReleaseComObject

 private void button1_Click(object sender, EventArgs e)
    {

        Excel03to07("D:\\TestExls\\TestExcelApp.XLS");

    }
    private void Excel03to07(string fileName)
    {
        string svfileName = Path.ChangeExtension(fileName, ".xlsx");
        object oMissing = Type.Missing;
        var app = new Microsoft.Office.Interop.Excel.Application();
        var wb = app.Workbooks.Open(fileName, oMissing, oMissing,
                        oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
        wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

        wb.Close(false, Type.Missing, Type.Missing);
        app.Quit();
        GC.Collect();
        Marshal.FinalReleaseComObject(wb);
        Marshal.FinalReleaseComObject(app);
   }

0

วิธีการส่วนใหญ่ใช้ได้ผล แต่กระบวนการ excel จะยังคงอยู่จนกว่าจะปิดการใช้งาน

เมื่อ kill excel กระบวนการเมื่อไม่สามารถเรียกใช้งานได้อีกครั้งในเธรดเดียวกัน - ไม่รู้ว่าทำไม


0

วิธีที่ถูกต้องในการปิดกระบวนการ excel ทั้งหมด

var _excel = new Application();
foreach (Workbook _workbook in _excel.Workbooks) {
    _workbook.Close(0);
}

_excel.Quit();
_excel = null;

การใช้ตัวอย่างกระบวนการนี้อาจปิดกระบวนการ excel ทั้งหมดโดยไม่คำนึงถึง

var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
    if (!string.IsNullOrEmpty(p.ProcessName)) {
        try {
            p.Kill();
        } catch { }
    }
}

นอกจากนี้ยังจะฆ่าอินสแตนซ์ที่ถูกต้องของ excel ที่เปิดอยู่นอกสภาพแวดล้อม VS กล่าวคือฉันมีแผ่นงาน excel อื่นเปิดอยู่ในแอป excel จริงรหัสของคุณก็ฆ่ามันเช่นกัน
ทำเครื่องหมาย

ขอบคุณที่อัปเดตบันทึก
Md. Alim Ul Karim


-1
        GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId);
        wb.Close(true,Missing.Value,Missing.Value);
        app.Quit();
        System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
        foreach (System.Diagnostics.Process p in process)
        {
            if (p.Id == iProcessId)
            {
                try
                {
                    p.Kill();
                }
                catch { }
            }
        }
}
[DllImport("user32.dll")]

private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

uint iProcessId = 0;

GetWindowThreadProcessId นี้ค้นหารหัสกระบวนการที่ถูกต้อง o excell .... หลังจากฆ่ามัน .... สนุกกับมัน !!!


-1
private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Unable to release the Object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

แม้ว่ารหัสนี้จะช่วยแก้ปัญหาได้ รวมถึงคำอธิบายว่าทำไมจึงแก้ปัญหานี้ได้จะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้อย่างแท้จริงและอาจส่งผลให้มีการโหวตเพิ่มขึ้น จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่แค่คนที่ถามตอนนี้ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
Dave
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.