2016-03-24 7 views
0

Ich schreibe ein Excel-Add-in und für 1 der Funktionen muss ich einige zusammenfassende Statistiken berechnen. Diese sollten als Namen entweder der gesamten Workbook oder einer einzelnen Worksheet hinzugefügt werden. Im Moment habe ich 2 Methoden, die jede Sache machen. Beide Methoden sehen jedoch fast identisch aus, mit dem Unterschied, dass der erste den Arbeitsbuch und der zweite den Arbeitsblatt hinzufügt.Generische Methode für Excel.Workbook und Excel.Worksheet

Gibt es eine Möglichkeit, diese Methode generischer zu machen, so dass basierend auf den übergebenen Argumenten überprüft werden konnte, ob das bereitgestellte Arbeitsblatt null ist und wenn ja, zur gesamten Arbeitsmappe hinzufügen?

/// <summary> 
    /// Generate dynamic summary statistics as <see cref="Name"/>s in the specified <see cref="Workbook"/>. 
    /// </summary> 
    /// <param name="range">The <see cref="Range"/> of the data that needs summary statistics.</param> 
    /// <param name="doCalculate">Defines which variables in the summary have to be calculated.</param> 
    public DynamicSummaryStatistics(Range range, SummaryStatisticsBool doCalculate) 
    { 
     var book = Globals.ThisAddIn.Application.ActiveWorkbook; 
     var name = ((Name)range.Name).Name; 
     if (doCalculate.Mean) Mean = book.Names.Add(name + "_MEAN", "=AVERAGE(" + name + ")"); 
     if (doCalculate.Variance) Variance = book.Names.Add(name + "_VAR", "=VAR.S(" + name + ")"); 
     if (doCalculate.StdDev) StdDev = book.Names.Add(name + "_STDEV", "=STDEV.S(" + name + ")"); 
     if (doCalculate.Minimum) Minimum = book.Names.Add(name + "_MINIMUM", "=MIN(" + name + ")"); 
     if (doCalculate.Quartile1) Quartile1 = book.Names.Add(name + "_QUARTILE1", "=QUARTILE.INC(" + name + ",1)"); 
     if (doCalculate.Median) Median = book.Names.Add(name + "_MEDIAN", "=MEDIAN(" + name + ")"); 
     if (doCalculate.Quartile3) Quartile3 = book.Names.Add(name + "_QUARTILE3", "=QUARTILE.INC(" + name + ",3)"); 
     if (doCalculate.Maximum) Maximum = book.Names.Add(name + "_MAXIMUM", "=MAX(" + name + ")"); 
     if (doCalculate.InterquartileRange) InterquartileRange = book.Names.Add(name + "_IQR", "=" + Quartile3.Name + "-" + Quartile1.Name); 
     if (doCalculate.Skewness) Skewness = book.Names.Add(name + "_SKEW", "=SKEW(" + name + ")"); 
     if (doCalculate.Kurtosis) Kurtosis = book.Names.Add(name + "_KURT", "=KURT(" + name + ")"); 
     if (doCalculate.MeanAbsDev) MeanAbsDev = book.Names.Add(name + "_AVEDEV", "=AVEDEV(" + name + ")"); 
     if (doCalculate.Mode) 
     { 
      Mode = book.Names.Add(name + "_MODE", "=MODE.SNGL(" + name + ")"); 
      try 
      { 
       Globals.ThisAddIn.Application.WorksheetFunction.Mode_Sngl(range); 
       HasMode = true; 
      } 
      catch 
      { 
       HasMode = false; 
      } 
     } 
     if (doCalculate.Range) Range = book.Names.Add(name + "_RANGE", "=" + Maximum.Name + "-" + Minimum.Name); 
     if (doCalculate.Count) Count = book.Names.Add(name + "_COUNT", "=COUNT(" + name + ")"); 
     if (doCalculate.Sum) Sum = book.Names.Add(name + "_SUM", "=SUM(" + name + ")"); 
    } 

    /// <summary> 
    /// Generate dynamic summary statistics as <see cref="Name"/>s in the specified <see cref="Worksheet"/>. 
    /// </summary> 
    /// <param name="sheet">The <see cref="Worksheet"/> on which the <see cref="Name"/>s should be generated.</param> 
    /// <param name="range">The <see cref="Range"/> of the data that needs summary statistics.</param> 
    /// <param name="doCalculate">Defines which variables in the summary have to be calculated.</param> 
    public DynamicSummaryStatistics(Worksheet sheet, Range range, SummaryStatisticsBool doCalculate) 
    { 
     var name = ((Name)range.Name).Name; 
     if (doCalculate.Mean) Mean = sheet.Names.Add(name + "_MEAN", "=AVERAGE(" + name + ")"); 
     if (doCalculate.Variance) Variance = sheet.Names.Add(name + "_VAR", "=VAR.S(" + name + ")"); 
     if (doCalculate.StdDev) StdDev = sheet.Names.Add(name + "_STDEV", "=STDEV.S(" + name + ")"); 
     if (doCalculate.Minimum) Minimum = sheet.Names.Add(name + "_MINIMUM", "=MIN(" + name + ")"); 
     if (doCalculate.Quartile1) Quartile1 = sheet.Names.Add(name + "_QUARTILE1", "=QUARTILE.INC(" + name + ",1)"); 
     if (doCalculate.Median) Median = sheet.Names.Add(name + "_MEDIAN", "=MEDIAN(" + name + ")"); 
     if (doCalculate.Quartile3) Quartile3 = sheet.Names.Add(name + "_QUARTILE3", "=QUARTILE.INC(" + name + ",3)"); 
     if (doCalculate.Maximum) Maximum = sheet.Names.Add(name + "_MAXIMUM", "=MAX(" + name + ")"); 
     if (doCalculate.InterquartileRange) InterquartileRange = sheet.Names.Add(name + "_IQR", "=" + Quartile3.Name + "-" + Quartile1.Name); 
     if (doCalculate.Skewness) Skewness = sheet.Names.Add(name + "_SKEW", "=SKEW(" + name + ")"); 
     if (doCalculate.Kurtosis) Kurtosis = sheet.Names.Add(name + "_KURT", "=KURT(" + name + ")"); 
     if (doCalculate.MeanAbsDev) MeanAbsDev = sheet.Names.Add(name + "_AVEDEV", "=AVEDEV(" + name + ")"); 
     if (doCalculate.Mode) 
     { 
      Mode = sheet.Names.Add(name + "_MODE", "=MODE.SNGL(" + name + ")"); 
      try 
      { 
       Globals.ThisAddIn.Application.WorksheetFunction.Mode_Sngl(range); 
       HasMode = true; 
      } 
      catch 
      { 
       HasMode = false; 
      } 
     } 
     if (doCalculate.Range) Range = sheet.Names.Add(name + "_RANGE", "=" + Maximum.Name + "-" + Minimum.Name); 
     if (doCalculate.Count) Count = sheet.Names.Add(name + "_COUNT", "=COUNT(" + name + ")"); 
     if (doCalculate.Sum) Sum = sheet.Names.Add(name + "_SUM", "=SUM(" + name + ")"); 
    } 
+0

Sie könnten eine private Methode haben, die eine 'Func ' und Sie '(format) => books.Names.Add (format)' für eine Arbeitsmappe und '(format) => Blatt. Names.Add (Format) 'für die Arbeitsblattmethode. Anstatt also zu versuchen, eine Methode zum Zugreifen auf die Arbeitsmappe oder das Arbeitsblatt bereitzustellen, wird allgemein eine Methode bereitgestellt, die die Methode zum Aufrufen des erforderlichen Objekts verwendet. –

+0

Vielen Dank für Ihre schnelle Antwort. Ist es möglich, ein kleines Beispiel in Pseudo-Code zu geben, damit ich weiß, wo ich anfangen soll? Ich habe nie zuvor mit dem, was du gesagt hast, gearbeitet. – Krowi

Antwort

2

Anstatt zu versuchen, den Zugriff auf die Workbook und Worksheet generic würde ich sagen zu machen, dass ein Func<string, string, Name> Bereitstellung, die den Zugriff erlaubt zu rufen entweder die Workbook oder Worksheet wäre eine bessere Methode.

public DynamicSummaryStatistics(Range range, SummaryStatisticsBool doCalculate) 
{ 
    var functionToRun = (arg1, arg2) => Globals.ThisAddIn.Application.ActiveWorkbook.Names.Add(arg1, arg2); 

    this.ComputeDynamicSummaryStatistics(range, doCalculate, functionToRun); 
} 

public DynamicSummaryStatistics(Worksheet sheet, Range range, SummaryStatisticsBool doCalculate) 
{ 
    var functionToRun = (arg1, arg2) => sheet.Names.Add(arg1, arg2); 

    this.ComputeDynamicSummaryStatistics(range, doCalcualte, functionToRun); 
} 

private void ComputeDynamicSummaryStatistics(Range range, SummaryStatisticsBool doCalculate, Func<string, string, Name> functionToRun) 
{ 
    var name = ((Name)range.Name).Name; 
    if(doCalculate.Mean) Mean = functionToRun(name + "_MEAN", "=AVERAGE(" + name + ")"); 
    if(doCalculate.Variance) Variance = functionToRun(name + "_VAR", "=VAR.S(" + name + ")"); 
    // etc. etc. 
} 

So wird dieser Spruch in der Funktion ComputeDynamicSummaryStatistics jeden-Zeit, dass ich functionToRun ich entweder rufen sheet.Names.Add(...) oder Globals.ThisAddIn.Application.ActiveWorkbook.Names.Add(...) basierend auf nenne welchem ​​Konstruktor aufgerufen wurde.

Der Zugriff auf entweder die Workbook oder die Worksheet ist der Methode völlig unbekannt und alles, was es jetzt betrifft, ist die Angabe des Namens zum Hinzufügen.

+0

Das funktioniert wie ein Zauber. Ich musste nur den Funktionsinitialisierer auf 'Func funcAdd = (name, refertzu) => sheet.Names.Add (name, referenziert);' um mit den 2 'string' Argumenten und der Rückgabe zu handeln, ändern Geben Sie 'Name' ein. Vielen Dank. – Krowi

+0

Ah Entschuldigung, ich habe komplett verpasst, dass Sie zwei String-Argumente übergeben, ich werde meine Antwort aktualisieren, um zu zeigen, was es sein soll. –

+0

Ich denke, es muss ein drittes Argument 'TResult' geben, das' Name' hier ist. – Krowi