.NET 6: How to use method overloading in console app Startup? - c#

.NET 6 offers boilerplate-removal in console applications Startup class. I try to run this simple test code:
Console.WriteLine("Hello, World!");
static void Test(int a, int b) { }
static void Test(int a, int b, int c) { }
I'm getting compiler error in the last line:
Error CS0128 A local variable or function named 'Test' is already defined in this scope
My question is: How to use method overloading in boilerplate free Startup pattern?

This
Console.WriteLine("Hello, World!");
static void Test(int a, int b) { }
is compiled to
[CompilerGenerated]
internal class Program
{
private static void <Main>$(string[] args)
{
Console.WriteLine("Hello, World!");
static void Test(int a, int b)
{
}
}
}
You see that the method is a local method, ie declaring inside Main. You cannot have 2 local functions with the same name. THis also fails;
see https://github.com/dotnet/docs/issues/17275
namespace Foo {
class Program {
// SerialPort port;
static void Main(string[] args) {
static void Test(int a) { };
static void Test(int a, int b) { };
}
}
for the same reason. The new short Main syntax has an awful lot of limitations

You can still create a class and put all the methods you want to overload. That's what I did. It works fine even if you can add access modifiers because as #pm100 said, the methods after compilation are in the main method
[CompilerGenerated]
internal class Program
{
private static void <Main>$(string[] args)
{
Console.WriteLine("Hello, World!");
static void Test(int a, int b)
{
}
}
}
so it's the same for access modifiers but hopefully the next version of .NET won't have this problem anymore but for now you can always use a previous version that keeps the "Main" method.

Related

Can I have two entry points in C#

Would it be possible to use two entry points in C# instead of just having the one. For example when I have this:
using System;
namespace learning
{
class cool
{
static void Main(string[] args)
{
}
}
}
Would it be possible to have another entry point such as secondary that the program executes once the main entry point has finished.
You may want to do something like this:
class Program {
public static void EntryPoint1(string[] args) {
// Code
}
public static void EntryPoint2(string[] args) {
// Code
}
public static void Main(string[] args) {
EntryPoint1(args);
EntryPoint2(args);
}
}
Just make sure to not modify args during EnteryPoint1 or if you want to, clone them like this:
class Program {
public static void EntryPoint1(string[] args) {
// Code
}
public static void EntryPoint2(string[] args) {
// Code
}
public static void Main(string[] args) {
EntryPoint1(args.Clone());
EntryPoint2(args.Clone());
}
}
In C#, you specify the entry point using the /main: compiler option.
Imagine that the code containing containing two main() methods as follow :
namespace Application {
class ClassA {
static void main () {
// Code here
}
}
class ClassB {
static void main () {
// Code here
}
}
To use ClassA.main() as your entry point, you would specify the following when compiling:
csc /main:Application.ClassA hello.cs
You can only have a single entry point, but you can write two separate methods, call the first one, and then the second one. You will achieve what you're describing.
using System;
namespace learning
{
class cool
{
static void Main(string[] args)
{
PartOne();
PartTwo();
}
void PartOne() {
// Something happens here
}
void PartTwo() {
// Something else happens here
}
}
}
Additionally (depending on how the program starts up) you can send in arguments to specify which method you want to execute (if you don't need both of them to execute). Then you can just do an "if/else" statement that will decide which method to run depending on the arguments passed into Main

Call method that has a Delegate instance parameter through Reflection C#

I have this C# code in an external assembly:
namespace Fancy
{
internal class Foo
{
public static void Window(string title, Foo.WindowFunction sceneViewFunc, int order)
{}
public delegate void WindowFunction(float x, float y);
}
}
And I have my code:
class A
{
public static void Draw(float x, float y)
{
// impl
}
static void Main(string[] args)
{
var newWindow = ?;
}
}
I want to call Fancy.Foo.Window() like
Fancy.Foo.Window("Window Name", new Foo.WindowFunction(A.Draw), 450);
inside my A class through Reflection.
How can I do it? Tried lot of different options no success :/
The documentation defines internal access modifier as follows
The type or member can be accessed by any code in the same assembly, but not from another assembly.
Not being able to access from outside of the assembly is the default and expected behaviour. But you can do that in multiple ways. If you have access to the source of the external assembly. You can mark your current assembly as a friend of the external assembly as shown below and recmpile it.
[assembly: InternalsVisibleTo("<Your assembly name>")]
Considering that you might not always have access to the source of external assembly, the same can be done using reflection by loading the assembly, creating an instance of the class and fetching the Non-Public members on the internal type. See how to access internal class using reflection. See also other ways to use internal class of another assembly.
Using reflection on external/third-party assemblies comes with its own caveats as the source of the assembly may change at any point in time, breaking your code.
Below is the code:
ClassLibrary1:
using System;
namespace ClassLibrary1
{
public class Foo
{
public static void Window(string title, WindowFunction sceneViewFunc, int order)
{
Console.WriteLine("Foo Window");
}
public delegate void WindowFunction(float x, float y);
}
}
Main Program.cs
using System;
using static ClassLibrary1.Foo;
namespace Algorithums
{
public class Program
{
public static void Draw(float x, float y)
{
// impl
}
public static void Main(string[] args)
{
RegisterWindowFunctionActionAndWindow("Window Name", 450);
Console.WriteLine("Hello World!");
Console.ReadLine();
}
public static void RegisterWindowFunctionActionAndWindow(string WindowName, int order)
{
var jsoType = Type.GetType("ClassLibrary1.Foo,ClassLibrary1");
var jso = Activator.CreateInstance(jsoType);
var mi = typeof(Program).GetMethod("Draw");
var d = Delegate.CreateDelegate(typeof(WindowFunction), mi);
var mi0 = jsoType.GetMethod("Window", new[] { typeof(string), typeof(WindowFunction), typeof(int) });
mi0.Invoke(jso, new object[] { WindowName, d, order });
}
}

Why the output default value is from Base class?

Why is the output B5, can someone explain?
class A
{
public virtual void M(int x=5)
Console.Write("A"+x);
}
class B:A
{
public override void M(int x=6)
Console.Write("B"+x);
}
class Program
{
static void Main(string[] args)
{
A a = new B();
a.M();
}
}
//Output is : B5
I expect the output to be B6, but the actual output is B5.
Default parameters don't work as you expect them.
They are constants that are hard-wired into method call during compilation. And during compilation, only known type is that of A.
Your code is equivalent to:
static void Main(string[] args)
{
A a = new B();
a.M(5);
}

Different behaviour of overlaoded method call if method is overriden

I have two overloaded methods MyMethod. One with an int as parameter the other with a long.
Calling this method from outside with a integer calls the MyMethod(int) member. But if the method with int is overridden then the MyMethod(long) is called. I do not understand why dot.net behaves like this. Can someone explain the technical background?
For me it looks like a bug.
Example 1. and 3. (see code below) behaves like I would expect. But the 2. one I cannot explain why the code calls the long method.
// 1. Normal Overloading
class Program
{
static void Main(string[] args)
{
int value = 123;
new MyClass().MyMethod(value);
// Output: Method INT
Console.ReadKey();
}
}
class MyClass
{
public void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
public void MyMethod(long value)
{
Console.WriteLine("Method LONG");
}
}
// 2. Combine Overriding with Overloading
class Program
{
static void Main(string[] args)
{
int value = 123;
new MyChildClass1().MyMethod(value);
// Output: Method LONG
Console.ReadKey();
}
}
class MyParentClass
{
public virtual void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
}
class MyChildClass1 : MyParentClass
{
public override void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
public void MyMethod(long value)
{
Console.WriteLine("Method LONG");
}
}
// 3. Inherit but use New for overloading
class Program
{
static void Main(string[] args)
{
int value = 123;
new MyChildClass2().MyMethod(value);
// Output: Method INT
Console.ReadKey();
}
}
class MyParentClass
{
public virtual void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
}
class MyChildClass2 : MyParentClass
{
public new void MyMethod(int value)
{
Console.WriteLine("Method INT");
}
public void MyMethod(long value)
{
Console.WriteLine("Method LONG");
}
}
It's not a bug, it's a planned behavior (but I agree this is a bit of confusing especially in comparison with others examples). From here:
There's one aspect of this behaviour which is particularly surprising though. What counts as a method being "declared" in a class? It turns out that if you override a base class method in a child class, that doesn't count as declaring it.

Calling functions when parameter is value or reference type in C#?

public class A
{
void methodA(int a){}
void methodA(ref int a){}
}
static void Main()
{
int a=1;
new classA().methodA(a);
}
In Main class, which method is called? Are methods in class A are overloaded? can overriding is possible on the bases of value or reference parameters? Please help out to make me clear.
After fixing your code:
public class ClassA
{
public void methodA(int a)
{
Console.WriteLine("Without ref");
}
public void methodA(ref int a)
{
Console.WriteLine("With ref");
}
}
class Program
{
static void Main(string[] args)
{
int i = 1;
var a = new ClassA();
a.methodA(i);
a.methodA(ref i);
Console.ReadKey(true);
}
}
You'll see that the first call will print 'Without ref' and the second 'With ref'. You could've done this yourself.
The manual says it's perfectly possible:
However, overloading can be done when one method has a ref or out parameter and the other has a value parameter, as shown in the following example.
class RefOverloadExample
{
public void SampleMethod(int i) { }
public void SampleMethod(ref int i) { }
}
new A().methodA(a);
will call the non-ref version.
new A().methodA(ref a);
will call the ref version.
In C#, you have to explicitly say if you're passing by reference.
Following calls are different
int a = 5;
methodA(a);
methodA(ref a );
ref keyword MSDN
overloading can be done when one method has a ref or out parameter and
the other has a value parameter, as shown in the following example
In your case it will call methodA(int a){} not the one with ref.
Your class should be:
public class A
{
public void methodA(int a)
{
}
public void methodA(ref int a)
{
}
}
If you want to call the overloaded method with ref keyword you need to specify ref in your method call. Like:
int a = 1;
A classAObj = new A();
classAObj.methodA(ref a);
The above code will resolved to the overloaded methodA(ref a)
public class A
{
void methodA(int a){}
void methodA(ref int a){}
}
static void Main()
{
int a=1;
new classA().methodA(a);
new classA().methodA(ref a)//You can add this to see the difference
}
Both are different from each other...
new classA().methodA(a);
new classA().methodA(ref a)

Categories

Resources