Hi Govert,
I think I suffered from some premature posting :) ... I didn't quite
finish my post before I submitted it, so here is some additions which
I excluded. Hopefully I can answer your questions at the end.
Some obvious advantages of custom marshalling by generating wrapper
functions:
-------------------------------------------------------------------------------------
* reduce the boiler plate marshalling code needed
eg public static double DoSomething(object input) {
double myInput = 2;
if !(input is ExcelMissing) {
myInput = toDouble(input);
}
return myInput * 4;
}
* make testing easier Assert.Equal(mycomplexObject,
excelMethod(...,List<DateTime>))
* use defaults eg public double DoIt(double arr = 4)
* wrap error handlers around each parameter so you know if the
marshalling or validation failed on that parameter
* use more complex input types for my functions eg List<DateTime> or
enums (eg better type safety)
* use reverse lookups of real types from excel (eg have a method that
describes an excel function and what it really expects eg double
myfunction(mydaybasisenum dayBasis) generates a method double
myfunction([ExcelRealType(TypeName=typeof(mydaybasisenum))] object
dayBasis)
* customise the errors slightly better (I know about the hooks)
* cater for ExcelMissing, ExcelError
* use methods on objects (ie not only static methods need to be used)
* instrumentation
* logging
An example:
-----------
The existing ExcelDNA code would look like this:
[ExcelFunction....]
public static double GetInterestRate(string yieldCurve, object date,
object dayBasis) {
// if in function wizard do something else
....
// check yield curve handle exists in cache, else throw
exception
....
// convert other parameters
....
// if they are missing, use the default
// if they are arrays, perhaps convert them to lists and replace
ExcelMissing to nulls?
return yc.InterestRate(....);
}
public class Y...
My goal was to only write the bare minimum code and leave the rest to
a framework.
new code:
public class YieldCurve {
[ExcelBoundMethod]
public double InterestRate( DateTime date, DayBasis dayBasis
DayBasis.Actual_365) {
//real code goes here
}
}
The solution in brief:
----------------------
A simple solution would be to introduce compile time aspects, but as I
see there is not much support for this in C#, I made used of
Microsoft's T4 templates.
The implementation becomes fairly simple. In the T4 template, iterate
through all the methods in every assembly which have the
ExcelBoundMethod attribute (I don't use ExcelFunction, to avoid
interfering with ExcelDNA). Then generate static ExcelDNA signatures
for each method, declaring the input parameters as Excel types.
Furthermore, generate marshalling code to marshal the Excel types into
C# types.
On to some of your points:
--------------------------
I guess there are 2 ways of extending DNA. Either keeping DNA simple
and having users generate wrapper methods which get compiled into
their projects, or letting DNA provide a marshalling interface and
allowing the users to register 'marhallers' of complex types. (Also,
attributing parameters would work).
I went the way of generating method bindings via T4. The ability to
inject code into method gives you lot's of flexibility. It means I can
do funky things besides marshalling... (instrumentation, logging etc)
I like java's compile time aspect's personally.
Just quickly on Object instantiation - There are a couple of
techniques I have used or thought about.
* For simpler objects, you could easy Attribute a constructor, which
could be generated at compile time as a DNA method. This returns a
unique string id to a dictionary entry. Another technique would be to
reflect on a list of name value pairs and reflectively set on an
object (which is added to the dictionary). A further method would be
to provide factory methods for each object. Often objects in a domain
have a hierarchy anyway. eg A market may have a YieldCurve object.
It there is any interest, (and I have the time), maybe I could expand
on this a bit.
thanks
Michael Tavares