In our product, we have things called "services" which are the basic means of communication between different parts of the product (and especially between languages—an in-house language, C, Python and .NET).
At present, code is like this (Services.Execute
utilising params object[] args
):
myString = (string)Services.Execute("service_name", arg1, arg2, ...);
I'd rather like to be able to write code like this and get the benefits of type checking and less verbose code:
myString = ServiceName(arg1, arg2, ...);
This can be achieved with a simple function,
public static string ServiceName(int arg1, Entity arg2, ...)
{
return (string)Services.Execute("service_name", arg1, arg2, ...);
}
But this is rather verbose, and not quite so easy to manage when doing it for scores of services, as I intend to be doing.
Seeing how extern
and the DllImportAttribute
work, I hope it should be possible to hook this up by some means like this:
[ServiceImport("service_name")]
public static extern string ServiceName(int arg1, Entity arg2, ...);
But I don't know how to achieve this at all and can't seem to find any documentation for it (extern
seems to be a fairly vaguely defined matter). The closest I've found is a somewhat related question, How to provide custom implementation for extern methods in .NET? which didn't really answer my question and is somewhat different, anyway. The C# Language Specification (especially, in version 4.0, section 10.6.7, External methods) doesn't help.
So, I want to provide a custom implementation of external methods; can this be achieved? And if so, how?
The C# extern keyword does very little, it just tells the compiler that the method declaration won't have a body. The compiler does a minimum check, it insists that you provide an attribute as well, anything goes. So this sample code will compile just fine:
class Program {
static void Main(string[] args) {
foo();
}
class FooBar : Attribute { }
[FooBar]
static extern void foo();
}
But of course it will not run, the jitter throws its hands up at the declaration. Which is what is required to actually run this code, it is the jitter's job to generate proper executable code for this. What is required is that the jitter recognizes the attribute.
You can see this done in the source code for the jitter in the SSCLI20 distribution, clr/src/md/compiler/custattr.cpp source code file, RegMeta::_HandleKnownCustomAttribute() function. That's code that's accurate for .NET 2.0, I'm not aware of additions to it that affect method calling. You'll see it handling the following attributes that relate to code generation for method calls, the kind that will use the extern keyword:
[DllImport], you no doubt know it
[MethodImpl(MethodImplOptions.InternalCall)], an attribute that's used on methods that are implemented in the CLR instead of the framework. They are written in C++, the CLR has an internal table that links to the C++ function. A canonical example is the Math.Pow() method, I described the implementation details in this answer. The table is not otherwise extensible, it is hard-baked in the CLR source code
[ComImport], an attribute that marks an interface as implemented elsewhere, invariably in a COM server. You rarely program this attribute directly, you'd use the interop library that's generated by Tlbimp.exe instead. This attribute also requires the [Guid] attribute to give the required guid of the interface. This is otherwise similar to the [DllImport] attribute, it generates a pinvoke kind of call to unmanaged code but using COM calling conventions. This can of course only work properly if you actually have the required COM server on your machine, it is otherwise infinitely extensible.
A bunch more attributes are recognized in this function but they don't otherwise relate to calling code that's defined elsewhere.
So unless you write your own jitter, using extern isn't a viable way to get what you want. You could consider the Mono project if you want to pursue this anyway.
Common extensibility solutions that are pure managed are the largely forgotten System.AddIn namespace, the very popular MEF framework and AOP solutions like Postsharp.