I have an ExcelDNA-based add-in (XLL) written in C# that does a bunch of different things, including register some UDFs with Excel for use in cell formulae.
The weird thing is that I have the following code for a UDF that successfully registers the 'ConvertUnit' function with Excel as a UDF, BUT ALSO ends up with the called function 'ConvertUnits' function from another class being registered as well:
// This is in a public static class called MyFunctions in the global namespace
[ExcelFunction(Description = "Convert value", IsMacroType = false)]
public static object ConvertUnit(
[ExcelArgument(Name = "Value", Description = "Value to be converted")] string value,
[ExcelArgument(Name = "Property Group", Description = "Type of property to be converted e.g. \"temperature\", \"diff_temperature\"")] string unitGroup,
[ExcelArgument(Name = "From Units", Description = "Units of measure to convert from")] string fromUom,
[ExcelArgument(Name = "To Units", Description = "Units of measure to convert to")] string toUom)
{ // UDF to convert a between UoM
double dblValue;
bool isValue = double.TryParse(value, out dblValue);
if (!isValue) return Common.errValue;
{ return UnitConversion.ConvertUnits(dblValue, unitGroup, fromUom, toUom); }
}
The UnitConversion.ConvertUnits function is in a different namespace, called DataTool:
public static object ConvertUnits(double value, string unitGroup, string fromUom, string toUom)
{ // Use this to expose via a UDF for users to convert between UoM for a specified unitGroup
string defaultUnit;
double toJM_Multiplier; double fromJM_Multiplier;
if (unitGroup == "temperature")
{
double tempVal;
switch (fromUom)
{
case "C":
tempVal = value;
break;
case "F":
tempVal = (value - 32.0) / 1.8;
break;
case "K":
tempVal = value - 273.15;
break;
case "R":
tempVal = (value - 491.67) / 1.8;
break;
default:
return Common.errUOM;
}
switch (toUom)
{
case "C":
return tempVal;
case "F":
return tempVal * 1.8 + 32.0;
case "K":
return tempVal + 273.15;
case "R":
return tempVal * 1.8 + 491.67;
default:
return Common.errUOM;
}
}
if (defaultUoM.ContainsKey(unitGroup))
{ // Get the default (JM) UoM for the unit group - should always exist but handle missing config file
defaultUnit = defaultUoM[unitGroup];
}
else
{ return Common.errConfigFile; }
if (!conversions.ContainsKey(unitGroup)) return Common.errConfigFile;
if (conversions[unitGroup].ContainsKey(fromUom))
{ // Get the conversion factor if it is mapped in the config file
toJM_Multiplier = conversions[unitGroup][fromUom];
}
else
{ return Common.errUOM; }
if (conversions[unitGroup].ContainsKey(toUom))
{ // Get the conversion factor if it is mapped in the config file
fromJM_Multiplier = conversions[unitGroup][toUom];
}
else
{ return Common.errUOM; }
if (toJM_Multiplier != 0.0)
{ return value / toJM_Multiplier * fromJM_Multiplier; }
else
{ return null; }
}
Then in the built XLL, I end up seeing both functions appearing in Excel as UDFs, despite there being no ExcelDNA content in my UnitConversion class. Why!?
By default, all the public static methods are registered in the AddIn.
Have a look here
I see both parameters which can help you:
<!-- Prevents every static public function from becomming a UDF, they will need an explicit [ExcelFunction] annotation. -->
<!-- Default value: false -->
<ExcelAddInExplicitExports></ExcelAddInExplicitExports>
<!-- Prevents automatic registration of functions and commands. -->
<!-- Default value: false -->
<ExcelAddInExplicitRegistration></ExcelAddInExplicitRegistration>