It looks cool on MSDN:
Specifies that the method is declared, but its implementation is
provided elsewhere.
So I tried it in a console application:
public class Program
{
[MethodImplAttribute(MethodImplOptions.ForwardRef)]
public static extern void Invoke();
static void Main(string[] args)
{
Invoke();
Console.Read();
}
}
Then what should I do now? Where can I provide the implementation of Program.Invoke?
The usage of ForwardRef goes pretty much like this:
consumer.cs
using System;
using System.Runtime.CompilerServices;
class Foo
{
[MethodImplAttribute(MethodImplOptions.ForwardRef)]
static extern void Frob();
static void Main()
{
Frob();
}
}
provider.cs
using System;
using System.Runtime.CompilerServices;
class Foo
{
// Need to declare extern constructor because C# would inject one and break things.
[MethodImplAttribute(MethodImplOptions.ForwardRef)]
public extern Foo();
[MethodImplAttribute(MethodImplOptions.ForwardRef)]
static extern void Main();
static void Frob()
{
Console.WriteLine("Hello!");
}
}
Now the magic sauce. Open a Visual Studio command prompt and type:
csc /target:module provider.cs
csc /target:module consumer.cs
link provider.netmodule consumer.netmodule /entry:Foo.Main /subsystem:console /ltcg
This uses one of the lesser known functionality of the linker where we're linking managed modules together. The linker is able to gel together same-shaped types (they need to have the exact same methods, etc.). ForwardRef is the thing that actually lets you provide implementation elsewhere.
This example is kind of pointless, but you can imagine things getting more interesting if a single method is implemented in a different language (e.g. IL).
My understanding is that ForwardRef acts in the same way as extern, and is intended for guiding the runtime when the language you are using lacks direct support (via extern in C#). As such, the usage should be very similar to the extern modifier, most notably using [DllImport(...)].
Related
In the Program.cs for .NET 5, you could add methods under the Main(string[] args) method. With .NET 6, the Main method exists, but isn't physically included in the Program.cs file by default. To that end, I'm wondering how you add methods to Program.cs. For example:
// .NET 5
public class Program
{
static void Main(string[] args)
{
// body
}
public static void MyMethodHere()
{
// method body
}
}
How would you add the MyMethodHere() class in .NET 6 in Program.cs without manually typing out the whole Program class and Main method?
You just type out the method that you require and then call it!.
Console.WriteLine("Hello, World from Main!");
MyMethodHere();
static void MyMethodHere()
{
Console.WriteLine("MyMethodHere says hello World!");
}
But you can still type it out in full the same as you done before.
What I have done several times for simple console programs is to create the project with .net 5, this then generates using the "old" template, and then I just update TargetFramework it to .net 6 before I do any coding.
See also the guide from MS: https://learn.microsoft.com/en-gb/dotnet/core/tutorials/top-level-templates
This would work as well:
SayHello();
void SayHello()
{
Console.WriteLine("Hello World");
}
Methods are possible, but without the access modifiers.
The compiler internally creates a static class.
.NET 6 has this new feature that allows minimal main. They unfortunately use it by default in new console projects. Its very confusing. Anyway you can write the old main just like you used to. You just have to type out all the code, or cut and paste from an old project
I was learning code contract but it doesn't throw me any error or anything. I am using Visual Studio 2019.
Here's the code:
using System.Diagnostics.Contracts;
namespace ConsoleApp1
{
class Calculations
{
public static void Division(string name)
{
Contract.Requires(!string.IsNullOrEmpty(name));
}
}
class Program
{
static void Main(string[] args)
{
string s = null;
Calculations.Division(s);
}
}
}
How is this not throwing me anything? I pretty much violated the contract when I call Division.
Most probably because of the following line in the documentation
Most methods in the contract class are conditionally compiled; that is, the compiler emits calls to these methods only when you define a special symbol, CONTRACTS_FULL, by using the #define directive. CONTRACTS_FULL lets you write contracts in your code without using #ifdef directives; you can produce different builds, some with contracts, and some without.
It is also mentioned in the documentation that once you setup and use the Code.Contracts UI, then the CONTRACTS_FULL is defined.
All, I'm new to C# and I'm trying to work through a problem that I'm having a hard time understanding.
I'm referencing a library in my code (which I've successfully added to my references). I've also identified the specific namespace within the library to bring in. However, when I initialize an instance of a class within said namespace I'm running into some issues.
The class in question has a constructor (I believe) that has an IntPtr argument. When I'm initializing an instance of the class in my code it's expecting me to provide it with an IntPtr argument, but I don't understand what exactly I should be providing. I know that IntPtr is a pointer to a space in memory, but what that means in my code I'm not sure.
Here is a link to the Library in question: https://github.com/filoe/cscore
The Namespace/Class in reference is in my code below.
using System;
using CSCore.CoreAudioAPI;
namespace EndpointController_POC_v0._1
{
class Program
{
static void Main(string[] args)
{
AudioEndpointVolume endPtCtrl = new AudioEndpointVolume(?);
endPtCtrl.SetMasterVolumeLevelScalar(1, Guid.Empty);
Console.ReadLine();
}
}
}
I have a C++ Dll "TheFoo.dll" with a method "Foo()"
I have access to other C++ code that uses this method by simply calling:
Foo();
I believe the Method does have the:
__declspec( dllexport )
So, with the reading I've done about P/Invoke, i thought i should be able to simply call the same method from my C# code:
namespace PInvokeExample1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
[DllImport(#"C:\MyFolder\TheFoo.dll")]
public static extern
void Foo();
private void button1_Click(object sender, RoutedEventArgs e)
{
Foo();
}
}
}
When i run it, i get an error:
Unable to find an entry point named 'Foo' in DLL 'C:\MyFolder\TheFoo.dll'.
Any ideas why it is not found?
The C++ language supports overloading, much like C# does. You could export an function void Foo(int) and a function void Foo(double). Clearly those two functions could not both be exported as "Foo", the client of the DLL wouldn't know which one to pick. So it is not.
The C++ compiler solves that problem by decorating the name of the function. Adding extra characters that makes a Foo(int) different from a Foo(double). You can see those decorated names by running Dumpbin.exe /exports foo.dll from the Visual Studio Command Prompt, that lists the name of the exported functions. Assuming your declaration was relevant, you'd see ?Foo##YAXXZ.
So the corresponding declaration in your C# program should be:
[DllImport("foo.dll", EntryPoint = "?Foo##YAXXZ",
ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern void Foo();
There are ways to change the C++ function declaration to make the C# declaration easier. Which is actually not a good idea, these decorated names actually help catch mistakes.
You should provide more information on your C++. Try using extern "C" __declspec(dllexport) instead. C++ exports with strange names so using extern "C" avoids that.
If you didn't declare it extern "C" in your dll, its name has likely been "mangled". You can use something like Dependency Walker to see what symbols your dll exports.
Consider following piece of code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace RemotingNonVirtualCall
{
class Program
{
static void Main(string[] args)
{
var domain = AppDomain.CreateDomain("Second Domain");
A extA = (A)domain.CreateInstanceAndUnwrap(typeof(A).Assembly.FullName, typeof(A).FullName);
Console.WriteLine(extA.CurrentDomain());
}
}
[Serializable]
sealed class A : MarshalByRefObject
{
public string CurrentDomain()
{
return AppDomain.CurrentDomain.FriendlyName;
}
}
}
Method A::CurrentDomain is non-virtual, class A is sealed. But CLR intercepts method call and redirect it to another instance. How it is possible? Is it some sort of voodoo magic? Does CLR make some exception in method calling for object inherited from MarshalByRefObject class? How is it performed?
Thanks for advance.
It's essentially magic, i.e. the ability to do this is built into the .NET runtime. The good news is that your code can also do this, if it needs to: http://msdn.microsoft.com/en-us/library/system.runtime.remoting.proxies.realproxy.aspx
The JIT compiler is keenly aware that it generates code for a proxy. You can have a look-see with the SSCLI20 source code, clr\src\vm\jithelpers.cpp, search for "proxy".