How Does Extern Work in C#

How does extern work in C#?

Consider reading section 10.6.7 of the C# specification, which answers many of your questions. I reproduce part of it here for your convenience:


When a method declaration includes an
extern modifier, that method is said
to be an external method. External
methods are implemented externally,
typically using a language other than
C#. Because an external method
declaration provides no actual
implementation, the method-body of an
external method simply consists of a
semicolon. An external method may not
be generic. The extern modifier is
typically used in conjunction with a
DllImport attribute,
allowing external methods to be
implemented by DLLs (Dynamic Link
Libraries). The execution environment
may support other mechanisms whereby
implementations of external methods
can be provided. When an external
method includes a DllImport attribute,
the method declaration must also
include a static modifier.


How does someone leverage the extern attribute?

  • Write your code in the unmanaged language of your choice.
  • Compile it into a DLL, exporting the entry point of your code.
  • Make an interop library that defines the method as an extern method in the given DLL.
  • Call it from C#.
  • Profit!

How would I go about looking into the source of extern methods like Object.InternalGetEquals()?

Go to https://github.com/dotnet/coreclr/tree/master/src/vm

What is the purpose of the extern modifier on an event?

I have never seen this before, and a search does not really bring up any real-world uses, but can find it in the Roslyn compiler testsuite:

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

public class C
{
[method: DllImport("c")]
public extern static event System.Action G;
}

The test verifies that this imports the add_G and remove_G functions from the c DLL. Since only the accessor methods are imported, there is no way for C or any of its users to raise the event, that can only be done by the external DLL.

I suspect it's just there for completeness. The extern keyword was already there, and it would quite possibly be more work to reject it in combination with events than to make it work.

As for your edit, properties, indexers, constructors, static constructors, finalizers, operators all have one thing in common: they're methods. Fancy methods, but methods nonetheless. The same for event accessors. And since methods can be extern, that applies to all methods unless the rules have specific exceptions. Specific exceptions require work, and the benefits of that work have to outweigh the costs. In this case, there are pretty much no benefits to rejecting extern in such cases.

When is it appropriate to use the extern keyword without using the [DllImport] attribute?

One case where I'd use it is if I were a Microsoft developer implementing a call to a method defined in the CLR itself. Like in GC._WaitForFullGCApproach:

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int _WaitForFullGCApproach(int millisecondsTimeout);

Note: no DllImport. Of course this is cheating a bit -- this is still a call to an unmanaged method, just not with an explicit reference to a DLL. Mere mortals cannot invoke such code, though, since it's valid only in the mscorlib assembly.

Another application of InternalCall is in interop types generated for COM:

namespace Microsoft.Office.Interop.Excel {
[DefaultMember("_Default")]
[ClassInterface(0)]
[ComSourceInterfaces("Microsoft.Office.Interop.Excel.AppEvents\0")]
[Guid("00024500-0000-0000-C000-000000000046")]
[TypeLibType(2)]
[ComImport]
public class ApplicationClass {
// ...
[DispId(302)]
[MethodImpl(MethodImplOptions.InternalCall)]
public virtual extern void Quit();
// ...
}
}

The attributes allow the runtime to resolve the method call as an invocation to a COM interface. This use of InternalCall is valid outside mscorlib, obviously. You would not typically write such code in C# yourself; it's generated on demand when you add a COM type library as a reference.

The C# language specification goes into slightly more detail than the MSDN:

The extern modifier is typically used in conjunction with a DllImport
attribute (§17.5.1), allowing external methods to be implemented by
DLLs (Dynamic Link Libraries). The execution environment may support
other mechanisms whereby implementations of external methods can be
provided.

From an implementation standpoint, marking a method extern only has the effect of setting the RVA (relative virtual address) of the method to 0, marking it as having no implementation. Attributes like DllImport (and MethodImpl) are necessary to describe to the runtime how to locate the method's actual implementation. This is described in secion I.9.4 of ECMA-335, "Method implementation metadata" (and DllImport and InternalCall seem to be the only ways currently available).

The C# compiler will allow you to mark a method as extern and not use any attribute to indicate where the implementation lives, but any type with such a method will result in a TypeLoadException at runtime.

When would I want to use extern?

Don't confuse unmanaged DLLs with .NET assemblies. Just because the extension is .dll doesn't mean you can add a reference to it.

Quite simply: If you want to call a C function in an unmanaged DLL, you use [DllImport(...)] and the static extern modifiers. Adding it as a reference will not work because it is not a .NET assembly.

If you want to call a method in a managed .NET assembly, you add it as a reference and then you can invoke the method directly using C# code.

Equal of c++ extern in c#

To create a global variable in C# you will have to create a public static field or property in a class:

class Globals {

public static int AnythingProperty { get; set; }

public static int AnythingField;

}

If the Globals class only contains static members (which the name indicates) then you can change the class declaration to static class Globals.

From within any other class you can then access the property or field:

class SomeClass {

public void SomeMethod() {
Globals.AnythingProperty += 1;
Globals.AnythingField = 2;
}

}

Having global variables in your code will increase coupling and can lead to subtle errors and hard to understand code. Most often there are alternatives to using global variables but at least you know how to now.

How can I implement my own type of extern?

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.

Why System.Math has extern methods for Sin, Cos, etc?

MethodImplOptions.InternalCall means the method is implemented natively by the common language runtime. It makes sense for mathematical operations as they are usually heavily optimized for the target platform. For instance, in x86 architecture, there is a single instruction that computes sine and cosine. A managed implementation is unlikely to be able to directly utilize such instructions.

Extern class used by an ASP.NET page

Creating classes in c# is very similar to creating classes in any modern, strongly typed, OO programming language. First you define the class, and then you instantiate it. There are many different ways to re-create the validation in your question, here's one.

Here is the class definition

public class Validator
{
private const string Username = "Carlos";
private const string Password = "236";

public bool Validate(string user, string pass)
{
return (user == Username && pass == Password);
}
}

To instantiate and use the class in your code (note the use of the ternary conditional operator instead of if/else, this keeps the code concise and readable)

protected void LoginBoton_Click(object sender, EventArgs e)
{
//instantiate the class defined above
var validator = new Validator();

//find the next page to redirect to
var redirectTo = validator.Validate(User.Text, Pass.Text) ? "Valid.aspx" : "Invalid.aspx";

//redirect the user
Response.Redirect(redirectTo);
}

C# is a deep language with a gentle learning curve, you may benefit from finding a good tutorial or book on the subject. There are a number of introductory tutorials from Microsoft that may be helpful.

Another thing to note, is that the word extern is a keyword in c#, that indicates managed code (i.e. code that runs in the CLR) wants to load and execute unmanaged code, (i.e. code that runs natively).

C# attributes used for information or to import extern functions?

Simply said, attributes are just metadata attached to classes or methods, at the very base.

The compiler, however, reads through your code, and runs specific actions for specific attributes it encounters while doing so, hardcoded into it. E.g., when it finds a DllImportAttribute on a method, it will resolve it to an external symbol (again, this is a very simplified explanation).
When it finds an ObsoleteAttribute, it emits a warning of deprecation.

Your own attributes (which you can create with a class inheriting from the Attribute base class) will not have an effect on the default compiler. But you (or other libraries) can also scan for them at runtime, opening up many possibilities and leading to your second question:

I typically use them to do meta programming. For example, imagine a custom network server handling packets of a specific format, implemented in different classes. Each packet format is recognized by reading an integer value. Now I need to find the correct class to instantiate for that integer.

  • I could do that with a switch..case or dictionary mapping integer -> packet which I extend every time I add a packet, but that is ugly since I have to touch code possibly far away from the actual Packet class whenever I add or delete a packet. I may not even know about the switch or dictionary in case the server is implemented in another assembly than my packets (modularity / extensibility)!
  • Instead, I create a custom PacketAttribute, storing an integer property set via the attribute, and decorate all my Packet classes with it. The server only has to scan through my assembly types at startup (via reflection) and build a dictionary of integer -> packet pairs automatically. Of course I could scan my assembly every time I need a packet, but that's probably a bit slow performance-wise.

There are APIs which are much more attribute heavy, like controllers in ASP.NET Core: You map full request URLs to methods in handler classes with them, which then execute the server code. Even URL parameters are mapped to parameters in that way.

Debuggers can also make use of attributes. For example, decorating a class with the DebuggerDisplayAttribute lets you provide a custom string displayed for the instances of the class when inspecting them in Visual Studio, which has a specific format and can directly show the values of important members.

You can see, attributes can be very powerful if utilized nicely. The comments give some more references! :)



Related Topics



Leave a reply



Submit