日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

淺談Excel開發(fā):四 Excel 自定義函數(shù)

 法效天地 2014-01-29

    我們知道,Excel中有很多內(nèi)置的函數(shù),比如求和,求平均,字符串操作函數(shù),金融函數(shù)等等。在有些時候,結(jié)合業(yè)務(wù)要求,這些函數(shù)可能不能滿足我們的需求,比如我想要一個函數(shù)能夠從WebService上獲取某只股票的最新價;我想要一個函數(shù)能夠獲取當(dāng)前的天氣情況,這些需求我們可以通過編寫Excel自定義函數(shù)(User Define Function ,UDF )來實現(xiàn),這樣,在Excel中直接調(diào)用我們的自定義函數(shù)即可滿足特定的業(yè)務(wù)需求,一般地,因為這種自定義函數(shù)的粒度相對較小,所以我們可以根據(jù)業(yè)務(wù)需求編寫很多基礎(chǔ)的自定義函數(shù),然后以這些自定義函數(shù)為基礎(chǔ),編寫各種復(fù)雜的分析報表。

    編寫UDF的方式有很多種,比如直接在VBA種編寫自定義函數(shù);如果您熟悉C++,可以將自定義函數(shù)編寫到XLL中,不熟悉也可以使用ExcelDNA這個開源的庫使用.NET技術(shù)也可以將您的代碼編譯為XLL;如果熟悉.NET,使用C#編寫自定義函數(shù)類庫,然后將類庫注冊成Com組件也可在Excel中調(diào)用。下面就這幾種方式簡要介紹,并給出其優(yōu)缺點。

 

1. 使用C# 類庫注冊的方式實現(xiàn)Excel自定義函數(shù)

    我自己對.NET 較熟悉,所以首先介紹這種在.NET中即可進(jìn)行Excel自定義函數(shù)開發(fā)的模式,這種方法相對簡單。在開始之前,還是回到我們之前對YY插件的規(guī)劃,我們的YY插件有天氣,財經(jīng),地圖等功能,現(xiàn)在我們假設(shè)需要一個天氣自定義函數(shù),通過該函數(shù)能夠獲取某個城市某一天的天氣情況,比如說氣溫。

    首先我們需要創(chuàng)建一個簡單的C#類庫,如下圖,其名為YYWeatherUDF。

Create Class Liberary for UDF

    然后,我們創(chuàng)建一個所有自定義函數(shù)的基類UDFBase.cs,在該類中,我們放一些基本的注冊Com組件所需要的一些操作以及屏蔽一些Object的對象的方法使其不要出現(xiàn)在Excel的UDF函數(shù)中來。有一點需要注意的是,在注冊及取消注冊為Com組件的時候,為避免Excel找不到mscoree.dll,需要往注冊表中寫入其全部路徑,下面的代碼即為實現(xiàn)這一功能。

public abstract class UDFBase
{
    /// <summary>
    /// 解決在某些機(jī)器的Excel提示找不到mscoree.dll的問題
    /// 這里在注冊表中將該dll的路徑注冊進(jìn)去,當(dāng)使用regasm注冊該類庫為com組件
    /// 時會調(diào)用該方法
    /// </summary>
    /// <param name="type"></param>
    [ComRegisterFunctionAttribute]
    public static void RegisterFunction(Type type)
    {
        Registry.ClassesRoot.CreateSubKey(
            GetSubKeyName(type, "Programmable"));
        RegistryKey key = Registry.ClassesRoot.OpenSubKey(
            GetSubKeyName(type, "InprocServer32"), true);
        key.SetValue("", System.Environment.SystemDirectory + @"\mscoree.dll",
            RegistryValueKind.String);
    }

    [ComUnregisterFunctionAttribute]
    public static void UnregisterFunction(Type type)
    {
        Registry.ClassesRoot.DeleteSubKey(
            GetSubKeyName(type, "Programmable"), false);
    }

    private static string GetSubKeyName(Type type, string subKeyName)
    {
        return string.Format("CLSID\\{{{0}}}\\{1}", type.GUID.ToString().ToUpper(), subKeyName);
    }
}

    將工程的AssemblyInfo.cs 中的[assembly: ComVisible(true)]。還有一點需要注意的是,Object類還有四個公共方法,如果直接繼承的話,這四個方法還是會出現(xiàn)在我們的UDF函數(shù)中,要避免Object對象的其中三個公共方法出現(xiàn)在UDF列表中,可以重寫對三個方法設(shè)置ComVisible自定義屬性。但是第四個GetType方法不允許重寫,所以還是會出現(xiàn)在UDF中。要解決這一問題,我們不能使用類了,要使用接口,然后將接口暴露為Interface,具體做法可以參見http:///questions/2817942/how-to-hide-gettype-method-from-comhttp:///questions/1592440/excel-2007-udf-how-to-add-function-description-argument-help 這里為了簡潔和取舍,暫采用抽象類的方式處理。

/// <summary>
///  將Object類的四個公共方法隱藏
///  否則將會出現(xiàn)在Excel的UDF函數(shù)中
/// </summary>
/// <returns></returns>
[ComVisible(false)]
public override string ToString()
{
    return base.ToString();
}

[ComVisible(false)]
public override bool Equals(object obj)
{
    return base.Equals(obj);
}

[ComVisible(false)]
public override int GetHashCode()
{
    return base.GetHashCode();
}

    以上這些代碼是一個在C# 創(chuàng)建一個UDF類的基本代碼,我們可以將該代碼保存為基類。

    現(xiàn)在我們要編寫我們自己的實際的UDF函數(shù)了,新建一個名為WeatherFunc的類,繼承自上面的UDFBase抽象類,并在類的屬性上添加一些自定義屬性,這些屬性在后面注冊為Com組件的時候需要用到。ClassInterface類的構(gòu)造函數(shù)中參數(shù)ClassInterfaceType.AutoDual表示兩邊都傳遞,這就回是的Object類的所有公共方法都會顯示出來,如果采用實現(xiàn)接口的方式,將該熟悉設(shè)置為None即可解決多余方法出現(xiàn)在UDF列表中的問題,這里不細(xì)講,繼續(xù)。

[Guid("5268ABE2-9B09-439d-BE97-2EA60E103EF6")]
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class WeatherFunc : UDFBase
{
    public WeatherFunc()
    { }
}

    其中Guid可以使用Visual Studio自帶的工具生成,如果我們不指定,則Visual Studio在將該類注冊為Com組件時,調(diào)用regasm工具的時候會自動生成一個Guid,在開發(fā)過程中,一般我們會手動指定一個Guid,這樣在調(diào)試的時候我們可以根據(jù)Guid在注冊表中去查找該項,看是否正常注冊為了Com組件。

    然后我們在WeatherFunc中定義三個public方法,分別為YY_Weather_Condition ,YY_Weather_Temperture和YY_Weather_WindSpeed 這三個函數(shù)分別用來獲取天氣描述,氣溫和風(fēng)速。 這里的天氣情況使用了Yahoo Weather API,您可以參考http://developer.yahoo.com/weather/,API請求的格式中w代表城市編號,u代表單位,以上海為例,其請求的url為http://weather./forecastrss?w=2151849&u=c,他的返回格式是一個xml文件。這里我創(chuàng)建了一個Weather類對該接口進(jìn)行了封裝,由于這里重點講解UDF,故不做展開。

/// <summary>
/// 根據(jù)城市和日期,返回當(dāng)天的天氣描述
/// </summary>
/// <param name="city">城市</param>
/// <param name="day">日期</param>
/// <returns></returns>
public String YY_Weather_Condition(String city, DateTime day)
{
    Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
    return weather.Condition.Text;
}

/// <summary>
/// 根據(jù)城市和日期,返回當(dāng)天的氣溫狀況
/// </summary>
/// <param name="city">城市</param>
/// <param name="day">日期</param>
/// <returns></returns>
public double YY_Weather_Temperature(String city, DateTime day)
{
    Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
    return weather.Condition.Temperature;
}

/// <summary>
/// 根據(jù)城市和日期,返回當(dāng)天的風(fēng)速
/// </summary>
/// <param name="city">城市</param>
/// <param name="day">城市</param>
/// <returns></returns>
public double YY_Weather_WindSpeed(String city, DateTime day)
{
    Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
    return weather.Wind.Speed;
}

    這樣我們的三個UDF函數(shù)已經(jīng)寫好了,然后右擊工程項目,在屬性設(shè)置-〉生成 注冊為Com組件。

Set the dll Register for Com Interop

    這里注冊為Com組件時,Visual Studio其實是去調(diào)用regasm 將類庫注冊為Com組件,并在注冊表里面寫入一些信息。在發(fā)布到客戶端上部署的時候,我們可以直接導(dǎo)入該類庫的相關(guān)注冊表信息,或者直接調(diào)用regasm在客戶的機(jī)器上寫入這些信息,在后面講到Excel插件安裝部署的時候,會說到這些。

    然后我們直接進(jìn)行編譯。因為注冊Com組件涉及對注冊表進(jìn)行操作,在XP以上系統(tǒng)中,需要管理員權(quán)限,如果當(dāng)前Visual Studio不是以管理員身份運行。則會出現(xiàn)下面錯誤:

Register dll failed due to the privilege

保存退出,然后右鍵選擇以管理員權(quán)限打開VS,然后重新編譯。

    完成之后,我們根據(jù)之前的GUID 5268ABE2-9B09-439d-BE97-2EA60E103EF6 到注冊表中去查找,可以看到,編譯并注冊為Com組件后會到注冊表中寫入一些信息,這些情況在安裝Office等軟件的時候,最后一步的時候,一般可以看到正在注冊組件,然后后面是不停閃動GUID,應(yīng)該是在做相同的工作。我機(jī)器上截圖如下。

Excel UDF Register Key

現(xiàn)在我們打開Excel軟件,在開發(fā)工具-〉加載項中,將我們的自定義函數(shù)加載進(jìn)來。

Excel Addin Manager For Addin

現(xiàn)在,在公式->插入函數(shù)中可以看到我們編寫的自定義函數(shù)。

Insert UDF

    可以看到我們之前編寫的兩個UDF函數(shù),那個GetType是因為我們繼承自抽象類的緣故,其中三個已經(jīng)被重寫對Com不可見,GetType方法不能被重寫,沒有被移除,前面介紹了采用暴露接口的方式可以解決這一問題,需要將我們所有的UDF函數(shù)以接口的形式定義,然后在類中實現(xiàn)。這里就不多講了。

    點擊相應(yīng)的函數(shù),即可彈出參數(shù)選擇框:

Insert UDF into Excel

    自此,采用.NET編寫自定義函數(shù)介紹完了,他的好處是編寫方便,如果您熟悉.NET的話,相當(dāng)于就是編寫了一個特殊的類庫。當(dāng)然也有一些缺點,比如說,在Excel中輸入函數(shù)的時候,沒有AutoComplete支持,并且在界面上不能顯示參數(shù)的解釋和函數(shù)的解釋,Com的注冊和注銷都需要對注冊表進(jìn)行讀寫操作,在安裝部署的時候可能需要一些注冊表讀寫權(quán)限以及需要某些殺毒軟件的放行,一般地,因為我們的插件再安裝的時候是一定需要道注冊表中注冊的,所以一般的UDF函數(shù)的注冊對注冊表的讀寫時是和插件安裝一同進(jìn)行的;UDF函數(shù)使用.NET 編寫容易反編譯;僅支持Excel 2003及以上版本。不過由于這種方式簡單,所以仍然是很多開發(fā)UDF函數(shù)的可選方案。

2. VBA 的方式編寫自定義函數(shù)

    相信使用Excel比較多的人對VBA比較熟悉,VBA其實就是Excel里面的腳本,通過VBA也可以編寫自定義函數(shù),存放到某個Sheet頁或者作為一個獨立的Excel腳本文件比如xla

文件存放。一般的,我們會將我們的自定義函數(shù)存在單獨的Excel腳本.xla文件中,然后在系統(tǒng)加載的時候,將該腳本文件加載進(jìn)來。然后就可以直接使用里面編寫的UDF函數(shù)了。

    這里我們打開一個Excel文件,然后按Alt+F11打開VBA編輯器。

Open VBA

然后可以看到VBA 的IDE界面了,這時候,我們對著工程文件點擊,新添加一個模塊:

Create a module in VBA

    在該模塊中寫兩個簡單的函數(shù)。這一回,我們要編寫查找天氣最高溫度,最低溫度的兩個函數(shù)。命名為YY_Weather_TemperatureHigh,YY_Weather_ TemperatureLow。這里先簡單寫個假數(shù)字。

VBA UDF

    完成后,保存為.xla文件。然后回到Excel界面,現(xiàn)在我們在單元格中輸入我們的自定義函數(shù)的時候,當(dāng)我們輸入YY的時候,就有AutoComplete提示了,Excel 2003以上版本會為我們列出所有匹配以YY開頭的內(nèi)置函數(shù)和自定義函數(shù)了。

ExcelNDA Intellisence

    Excel函數(shù)只能提示界面上,按上,下鍵可以選擇,按Tab鍵確認(rèn)。輸入YY_Weather_TemperatureHigh的時候,單元格會返回30,輸入YY_Weather_TemperatureLow,單元格返回20,這兩個數(shù)字是我們硬編碼進(jìn)去的。這就是在VBA中編寫UDF函數(shù)的方式,簡單吧。如果邏輯比較簡單的話,您完全可以使用VBA語言來實現(xiàn)您的邏輯,比如說在VBA里面去查詢數(shù)據(jù)庫,去訪問WebService等等。

    如果您對VBA不熟悉的話,也沒關(guān)系,VBA中也可以調(diào)用C# 類庫中編寫的方法。我們可以使用VBA來編寫UDF函數(shù)的簽名,然后在VBA方法體內(nèi)調(diào)用C# 里面的方法?,F(xiàn)在我們將前面的兩個取最高,最低氣溫的函數(shù)換成我們之前寫好的通過Weather類獲取氣溫的代碼。

    要在VBA中調(diào)用C#中的方法,首先我們需要在第二篇文章中的SharedAddin程序的基礎(chǔ)上進(jìn)行,我們添加FunctionHelper類,并讓其繼承自StandardOleMarshalObject對象,然后提供一些對Weather函數(shù)進(jìn)行包裝的方法。代碼如下:

public class FunctionHelper:StandardOleMarshalObject
{
    public object GetWeather_TemperatureHigh(string city,DateTime day)
    {
        Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
        return weather.Forecast.Days[0].High;
    }

    public object GetWeather_TemperatureLow(string city, DateTime day)
    {
        Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
        return weather.Forecast.Days[0].Low;
    }
}

    然后,在Connect類的OnConnection中將ComAddin實例對象的Object的屬性設(shè)置為FunctionHelper實例對象:

public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
    applicationObject = application as Application;
    addInInstance = addInInst as COMAddIn;
    addInInstance.Object = new FunctionHelper();

    if (applicationObject.Version == "11.0")
    {
        if (menuDesigner == null)
        {
            menuDesigner = new MenuDesigner(applicationObject);
        }
        menuDesigner.AddMenus();
        menuDesigner.AddToolBars();
    }
}

    然后在VBA中,我們根據(jù)ProgId查找我們的插件。

Public Function GetCOMAddIn(Optional addInName As String) As COMAddIn
    Dim YYAddIn As COMAddIn
    If addInName = "" Then
        addInName = "YYSharedAddin"
    End If
    Dim addInItem As COMAddIn
    For Each addInItem In Application.COMAddIns
        If addInItem.Description = addInName Then
            Set YYAddIn = addInItem
            Exit For
        End If
    Next addInItem
    Set GetCOMAddIn = YYAddIn
End Function

    這里我們之前的插件叫YYSharedAddin,然后改寫我們的之前寫過的兩個函數(shù):

'獲取名為city的城市的當(dāng)天的最高氣溫
Function YY_Weather_TemperatureHigh(city As String, day As Date)
    Dim YYAddIn As COMAddIn
    Dim dataQuery As Object
    Set YYAddIn = GetCOMAddIn("YYSharedAddin")
    Set dataQuery = YYAddIn.Object
    YY_Weather_TemperatureHigh = dataQuery.GetWeather_TemperatureHigh(city, day)
End Function
'獲取名為city的城市的當(dāng)天的最低氣溫
Function YY_Weather_TemperatureLow(city As String, day As Date)
    Dim YYAddIn As COMAddIn
    Dim dataQuery As Object
    Set YYAddIn = GetCOMAddIn("YYSharedAddin")
    Set dataQuery = YYAddIn.Object
    YY_Weather_TemperatureLow = dataQuery.GetWeather_TemperatureLow(city, day)
End Function

    可以看到Y(jié)YAddin.Object對象在我們的Connect類的OnConnect的時候已經(jīng)賦值為了FunctionUtility的實例類,所以后面我們在VBA里可以直接調(diào)用里面的C# 方法了。

    將上面的VBA保存為Excel .xla格式的宏文件。然后在VBA中和Visual Studio中C#函數(shù)方法體內(nèi)設(shè)置斷點,在Sheet頁中輸入我們的自定義函數(shù),然后可以看到VBA中的斷點被命中,注意在VBA IDE中,逐步運行調(diào)試的快捷鍵是F8,當(dāng)調(diào)試我們的dataQuery.GetWeather_TemperatureHigh這一句時,會跳到Visual Studio中的C#函數(shù)內(nèi)部,在VS中逐步調(diào)試的快捷鍵是F11,有意思吧。

F8 Debug VBA

    F11 Debug C#

    一般地,我們會將自定義UDF的簽名放到Excel 宏文件中以.xla文件保存,然后在方法體內(nèi)調(diào)用C#方法。以YY插件項目為例,當(dāng)程序運行的時候,在Connect類的OnConnect方法中我們可以使用以下方法加載.xla宏腳本文件到Excel中。

string basePath = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName;
LoadUDFs(basePath + "\\YYFunc.xla", true);
public bool LoadUDFs(string progID, bool load)
{
    bool loaded = false;
    try
    {
        if (File.Exists(progID))
        {
            AddIn udfAddIn = applicationObject.AddIns.Add(progID, true);
            udfAddIn.Installed = load;
            loaded = udfAddIn.Installed;
        }
    }
    catch { loaded = false; }

    return loaded;
}

    其中progID傳入我們腳本文件名加路徑,load為true。

    一般地,采用VBA的方式來編寫UDF函數(shù)簡單快捷,而且比較靈活方便調(diào)試,對于一些復(fù)雜的邏輯,可以將方法體的實現(xiàn)邏輯放置到C#代碼中,在Excel 03以上版本,還有Excel智能提示的支持,在注冊的時候,不需要對注冊表進(jìn)行讀寫操作。但是這種方式也有一些缺點:

  • VBA腳本安全性比較差,雖然可以對我們的腳本設(shè)置密碼,但這種密碼相當(dāng)容易被破解,破解的手段并不需要太復(fù)雜的枚舉或者遍歷邏輯,在前一篇文章中我們可以看到,破解的過程只需要將原先的腳本文件的保護(hù)密碼設(shè)置為另外一個密碼覆蓋之前的密碼即可,然后再次打開用這個密碼打開,然后取消密碼保護(hù)即可。
  • VBA腳本是一種解釋型的腳本語言,運行的時候是逐條語句邊解釋邊執(zhí)行的,這些和采用之前的Com組件方式的編譯為二進(jìn)制和后面直接編譯為xll的方式相比,運行效率較低。

3. XLL方式編寫自定義函數(shù)

    XLL是Excel自97版本就支持的一種外接二進(jìn)制插件,其運行速度較前面的兩種方式快,并且有更多強(qiáng)大的功能,但是XLL通常使用C或者C++編寫,對于開發(fā)者的要求較高。關(guān)于XLL開發(fā)在第一篇文章的參考資料中有一本Financial Applications using Excel Add-in Development in C / C++ 講的比較深入,有興趣的同學(xué)可以看看。

    幸運的是,有一個名為ExcelDNA的開源庫使得我們使用.NET語言即可編寫XLL程序。使用ExcelDNA很簡單,官網(wǎng)上的幫助文檔也很詳細(xì),這里簡要介紹一下如何使用ExcelDNA來編寫XLL自定義函數(shù)。當(dāng)然一開始我們需要到官網(wǎng)上下載安裝包:

    先建一個C# 類庫,然后引用下載文檔中的ExcelDna.Integration.dll,創(chuàng)建兩個公共的靜態(tài)的方法,這里為了完善我們的歪歪天氣函數(shù),我們創(chuàng)建兩個函數(shù)YY_Weather_Condition,YY_Weather_Sunrise分別用來獲取對天氣的描述信息和當(dāng)天的日出時間。

public class YYWeather
{
    [ExcelFunction(Description = "獲取指定城市的最新的天氣信息")]
    public static string YY_Weather_Condition(string city, DateTime day)
    {
        Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
        return weather.Condition.Text;
    }

    [ExcelFunction(Description = "獲取指定城市的日出時間")]
    public static DateTime YY_Weather_Sunrise(string city, DateTime day)
    {
        Weather weather = new Weather(city, Weather.TemperatureUnits.Celcius);
        return weather.Astronomy.Sunrise;
    }
}

    然后在項目中添加一個名為YYWeather.dna的文本文件。

<DnaLibrary Name="YY Weather Fucntion" RuntimeVersion="v4.0">
  <ExternalLibrary Path="YYWeatherUDFExcelDNA.dll" />
</DnaLibrary>

    然后將安裝包內(nèi)的ExcelDna.xll文件拷貝到項目內(nèi),并將其命名為YYWeather.xll,然后將其包含在項目中,設(shè)置其生成屬性,保證其在編譯時會拷貝到生成目錄下。

Excel DNA Pack Directory

    點擊生成的YYWeather.xll文件,然后先建一個Sheet頁,在打開的Excel Sheet頁中輸入YY,可以看到,我們之前建立的兩個自定義函數(shù)給予了提示。

ExcelNDA Intellisence

    選擇天氣狀況函數(shù),輸入城市和日期,可以看到返回了正確的天氣狀況信息,多云天氣

ExcelDNA Sh Weather

    另外在插入函數(shù)的時候,可以看到,對函數(shù)和參數(shù)有提示:

ExcelDNA Insert Function

    我們選擇查詢?nèi)粘龊瘮?shù),輸入城市和時間之后,可以看到能夠返回正確的結(jié)果。

ExcelDNA Sh Sunrise

    另外,在使用ExcelDNA時,比如上面的例子中,我們可以看到一堆的xll, dna, dll文件,不方便發(fā)布和部署。ExcelNDA提供了一個打包工具,可以將這些文件打包成一個xll文件,使用下載包內(nèi)的默認(rèn)打包程序ExcelDnaPack.exe即可實現(xiàn)這一功能,將ExcelDNAPack.exe拷貝到生成目錄,并在cmd下將當(dāng)前目錄切換到生成目錄下,命令行下運行程序,并將YYWeather.dna作為參數(shù)傳遞進(jìn)行:

Excel DNA Pack

    程序會生成YYWeather-packed.xll,這個即為生成好的xll文件,他會將dll中的內(nèi)容打包到xll中去,分發(fā)部署的時候,只需要將這個文件發(fā)布到用戶的機(jī)器上即可。

    一般地,在實際的開發(fā)環(huán)境中,以歪歪插件為例,和加載xla宏腳本文件一樣,在Connect的Onconnect方法中調(diào)用之前的LoadUDFs傳入該xll的完整路徑和文件名即可使用里面的自定義函數(shù)了。

string basePath = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName;
LoadUDFs(basePath + "\\YYWeather-packed.xll", true);

    ExcelDNA功能強(qiáng)大,這里只是簡要介紹了如何使用.NET語言編寫UDF函數(shù),ExcelDNA支持VBA語言,F(xiàn)#語言,還可以實現(xiàn)Ribbon菜單,RTD函數(shù),異步UDF函數(shù)等,這些后面會介紹。

    借助ExcelDNA編寫xll的UDF有很多優(yōu)點,比如說,運行速度快;Excel 2003以上版本支持函數(shù)的AutoComplete;支持函數(shù)和函數(shù)參數(shù)的注釋;不用對注冊表進(jìn)行讀寫;使用.NET 借助ExcelDNA開發(fā)門檻相對較低等優(yōu)點,在大多數(shù)情況下是比較理想的解決方案。

    另外,ExcelDNA的函數(shù)提示,僅支持1000個UDF,就是說超過1000個,當(dāng)您在Excel中輸入的時候,下拉提示框中,超出的部分函數(shù)可能不會出現(xiàn)。這可能是ExcelDNA的開發(fā)者考慮到過多的提示項對增加內(nèi)存消耗的原因。解決方法很簡單,您只需要下載ExcelDNA的源代碼,搜索1000,然后改為您想要的數(shù)字,然后在有些地方添加一些代碼。編譯一下即可。

    最后,使用上面的方式創(chuàng)建好了UDF之后,我們來創(chuàng)建一個簡單的天氣預(yù)報報表,我錄制了一個小動畫,如下圖,您應(yīng)該可以體會到Excel自定義函數(shù)的強(qiáng)大用處:

Weather Report

4. 結(jié)語

    Excel 中的自定義函數(shù)極大地擴(kuò)充了Excel的應(yīng)用領(lǐng)域,他也是Excel插件和業(yè)務(wù)邏輯的一個極好的接入點,通過Excel UDF函數(shù),您可以在此基礎(chǔ)上創(chuàng)建各種靈活的分析報表,構(gòu)建各種分析模型。本文簡要介紹了常見的三種編寫Excel UDF函數(shù)的方法,他們是采用.NET 托管代碼注冊為Com組件的方式,純VBA腳本和VBA調(diào)用.NET 類庫方式,以及借助Excel結(jié)合.NET 編寫xll的方式,三種方式各有優(yōu)缺點,現(xiàn)簡單總結(jié)如下:

方式

優(yōu)點

缺點

.NET Automation Add-Ins

1. 簡單,有.NET基礎(chǔ)即可。

2. 不需要借助任何第三方類庫即可實現(xiàn)。

3. 運行速度較快

4. 安全性較高

1. Excel 2003版本不支持AutoComplete

2. 在插入函數(shù)界面上,不支持函數(shù)及參數(shù)注釋

3. 需要對注冊表進(jìn)行讀寫操作。

VBA UDF

1. 簡單靈活易調(diào)試,有VBA基礎(chǔ)即可編寫,其實現(xiàn)既可以全部使用VBA,也可以在VBA中調(diào)用其它第三方類庫。

2. 擁有Excel 函數(shù)的智能提示的支持。

1. 安全性較差,非常容易被破解。

2. 插入函數(shù)界面上,不支持函數(shù)體及參數(shù)注釋

3. 運行效率低下,和編譯型語言相比,VBA本質(zhì)上是解釋型語言,邊解釋邊執(zhí)行,效率慢。

XLL

1. 運行速度快,由于事先編譯為了二進(jìn)制代碼,直接加在到內(nèi)存中執(zhí)行,較VBA方式快。

2. 安全性較高,一般采用C或者C++ 編寫,代碼發(fā)布后為二進(jìn)制,反編譯難度大。

3. 擁有Excel函數(shù)智能提示支持。

4. 插入函數(shù)界面支持函數(shù)體和函數(shù)參數(shù)注釋。

1.采用純C或者C++開發(fā)難度較大。采用ExcelDNA支持.NET 編寫XLL大大降低開發(fā)難度。但是這是在第三方工具的支持下進(jìn)行的。

    下文將會介紹Excel中的另外一類比較重要的函數(shù),Real Time Data 即RTD函數(shù),這一類型的函數(shù)可以實現(xiàn)諸多強(qiáng)大的功能,比如在Excel中實現(xiàn)股票行情信息的實時刷新,實現(xiàn)Excel 異步自定義函數(shù)功能等等,敬請期待。

    本文所有代碼點擊此處下載,希望本文對您了解Excel自定義函數(shù)有所幫助。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多