Passing Method Call with arguments already specified - c#

I would like to call a methodA with parameters already specified from another method.
So I want to pass the method call and arguments as a parameter to MethodB and once it's done some processing, call the MethodA with arguments specified.
I know i can pass the call as a methodB as a delegate parameter and then also pass the parameters like so :
static void Main( string[] args )
{
MethodB(1, 2, Add);
Console.ReadLine();
}
public static void Add(int i, int j)
{
Console.WriteLine(i+j);
}
static public class DelegateWithDelegateParameter
{
public static void MethodB(int param1, int param2, Action<int, int> dAction)
{
dAction(param1, param2);
}
}
Wondering, if it's possible to do this with the parameters already specified rather than having to pass parameters ParamA,ParamB to MethodB from Main already specified. Was just wondering. Hope this make sense, please let me know if you want more detail.

If I'm following what you are asking, to get what you want you need to wrap your call to Add in a delegate that holds it's parameters. This is easy to do using lamda syntax:
static void Main( string[] args )
{
MethodB(() => Add(1, 2));
Console.ReadLine();
}
public static void Add(int i, int j)
{
Console.WriteLine(i+j);
}
static public class DelegateWithDelegateParameter
{
public static void MethodB(Action dAction)
{
dAction();
}
}
The statement () => Add(1,2) creates a new Action delegate that is defined to call Add() with the parametes 1,2.

I think what you want is:
static object InvokeMethod(Delegate method, params object[] args){
return method.DynamicInvoke(args);
}
static int Add(int a, int b){
return a + b;
}
static void Test(){
Console.WriteLine(InvokeMethod(new Func<int, int, int>(Add), 5, 4));
}

You can do it through Delegate. declare a delegate first and hook your method to it like
public delegate void adddelegate(int a, int b);
class Program
{
static void Main(string[] args)
{
adddelegate adddel = new adddelegate(Add);
DelegateWithDelegateParameter.MethodB(1, 2, adddel);
Console.ReadLine();
}
public static void Add(int i, int j)
{
Console.WriteLine(i + j);
}
}
static public class DelegateWithDelegateParameter
{
public static void MethodB(int param1, int param2, adddelegate dAction)
{
dAction(param1, param2);
}
}

Related

How does unit test project test main()

I have a simple .net core console project in VS2019 as follows.
public class Program
{
public static int Sum(int x, int y)
{
return x + y;
}
public static void Main(string[] args)
{
Func<int, int, int> sum = Sum;
Console.WriteLine(sum(10, 10));
}
}
My question is how to create a unit test project to test main().
The static void method is that you can only verify if it interacts with the input argument or static members. A better approach is to delegate all logic to separate component and test it instead. Then it doesn't matter which type of project it is. You can just create a Unit Test project and test your code.
public static void Main(string[] args)
{
var component = new Component();
component.Execute(args);
}
Example component:
public class Component
{
public static int Sum(int x, int y)
=> x + y;
public void Execute(string[] args)
{
Func<int, int, int> sum = Sum;
Console.Write(sum(10, 10));
}
}
Test:
[Fact]
public void Test()
{
//assert
var stringWriter = new StringWriter();
Console.SetOut(stringWriter);
var component = new Component();
component.Execute(It.IsAny<string[]>());
var output = stringWriter.ToString();
Assert.Equal("20", output);
}

How to use a ref parameter in a thread if "Error CS1628: Cannot use in ref or out parameter inside an anonymous method, lambda or query expression"?

I am trying to write a tweening class, and in order to do so I have a static Tweener.TweenTo method. In it, we start a thread in order to not hold up external operations. The method looks like this:
public static void TweenTo<T>(ref ITweenable<T> obj, T target, double ms)
{
new System.Threading.Thread(() => {
System.Threading.Thread.Sleep(5000)
obj.DoStuff(5,5) //throws exception because obj is a ref parameter
}).Start()
}
I understand that using the ref parameter in the lambda means that it may be a dangling reference, but I need to be able to use it in case the user tries to pass a value type or struct to the method. I have tried using parameterized thread start, but that coerces things to an object, which I cannot use (unboxing etc.). I have also tried using a wrapper class that holds a pointer to it, but this runs in to complications later down the line.
I would like a way of using this ref parameter in the thread, and ideally preserving its lifetime inside it.
Any help is appreciated :D
Edit: Olivier's answer close to what I need, but MyClass would be a struct in some cases, and it will duplicate whenever it can. This means that it would lose the reference and give values from the wrong instance.
Edit 2: example struct
public struct MyStruct : ITweenable<T> {
int x;
int y;
public MyStruct(int X) {
this.x=X;
}
public void DoStuff(int newX, int newY) {
this.x=newX;
this.y=newY;
}
}
public interface ITweenable<T> {
void DoStuff(int newX, int newY);
}
Edit 3: I haven't tested this so when I have I will give it as an answer - have tested now, doesn't work:
public static void TweenTo<T>(ITweenable<T> obj, T target, double ms)
{
Func<ITweenable<T>> getTween = ()=>{return obj;}
new System.Threading.Thread(() => {
System.Threading.Thread.Sleep(5000)
getTween().DoStuff(5,5);
}).Start()
}
I'd suggest passing an Action<ITweenable<T>> to enable the assignment. Like this:
public static void TweenTo<T>(ITweenable<T> obj, Action<ITweenable<T>> update, T target, double ms)
{
new System.Threading.Thread(() =>
{
obj.DoStuff();
update(new Tweenable<T>());
}).Start()
}
Using an intermediate local var
Without considering the design and the reason for having the parameter by ref, nor any thread concurrency and interlocking management, just use an intermediate local var:
public static void TweenTo<T>(ref ITweenable<T> obj, T target, double ms)
{
var instance = obj;
new System.Threading.Thread(instance.DoStuff).Start();
}
Test
public interface ITweenable<T>
{
void DoStuff();
}
public class MyClass : ITweenable<int>
{
public void DoStuff()
{
Console.WriteLine("It works!");
Console.WriteLine("Press any key to exit the side thread.");
Console.ReadKey();
}
}
static private void Test()
{
var instance = (ITweenable<int>)new MyClass();
TweenTo(ref instance, 10, 20);
Console.WriteLine("Main thread ended.");
}
Output
Main thread ended.
It works!
Press any key to exit the side thread.
Remark for struct and code added in the question
It works the same, for the code and the case provided:
public interface ITweenable<T>
{
T X { get; }
T Y { get; }
void DoStuff(T newX, T newY);
}
public struct MyStruct : ITweenable<int>
{
public int X { get; private set; }
public int Y { get; private set; }
public void DoStuff(int newX, int newY)
{
Thread.Sleep(2000);
X = newX;
Y = newY;
Console.WriteLine("It works!");
}
}
public static void TweenTo<T>(ref ITweenable<T> obj, T target, double ms)
{
var instance = obj;
new System.Threading.Thread(() => instance.DoStuff((T)(object)10, (T)(object)10)).Start();
Console.WriteLine("Exiting TweenTo.");
}
Test
static private void Test()
{
var instance = (ITweenable<int>)new MyStruct();
Console.WriteLine("X is " + instance.X);
TweenTo(ref instance, 10, 20);
Console.WriteLine("Main thread ended.");
Console.WriteLine("Wait for the 'It Works' and press any key to continue main thread.");
Console.ReadKey();
Console.WriteLine("X is now " + instance.X);
Console.ReadKey();
}
Output
X is 0
Exiting TweenTo.
Main thread ended.
Wait for the 'It Works' and press any key to continue main thread.
It works!
X is now 10
Values by reference cannot be used across threads or in any deferred execution because .NET cannot enforce its memory management.
The struct in the ref lives on the stack of the calling function and can only be used when inside the scope of that function call.
The struct is a field in an other class and the reference is a pointer pointing to somewhere in the middle of the objects memory. The Garbage Collector cannot track these pointers and they are not allowed to live longer than the function call that created this reference. This function call has the original pointer to the object on its stack and with that the Garbage Collector can track the object.
So, in short, objects that need to be tweenable cannot be structs. The only solution is to make the class that contains this struct tweenable. Or if the tweenables are contained in an array implement a helper like this:
public class TweenableArray<T> : ITweenable<T>
{
private readonly ITweenable<T>[] _data;
public TweenableArray(ITweenable<T>[] data)
{
_data = data
}
void DoStuff(int newX, int newY)
{
for (var i = 0; i < _data.Length; i++)
_data[i].DoStuff(newX, newY)
}
}
Provided that newX and newY can be used for the whole array.

Assigning to a variable by reference?

Thanks to the kind folks who answered my previous question from a few days ago, I now know how to pass arguments by reference:
static void Main()
{
int i = 0;
Add(ref i, 100);
// now i == 100
}
static void Add(ref int arg, int increment)
{
arg += increment;
}
But is there a way for me not to just pass i by reference, but actually store its location in another variable? By that I mean use i like I did in my example; affecting the original instance, but in a way that's permanently linked and not leaving scope.
I vaguely know that I could use a pointer to determine the location in unsafe context but I was wondering if I could do this without any of that, or if it is just recommended to use the unsafe method.
If you are using C# 7 you can use ref local and ref return to store an updateable reference to any field.
In this example I change the private field _privateField from 0 to 100 from outside Foo, the class in which it is defined, by returning it as a ref int and updating it by reference.
class Foo
{
private int _privateField = 0;
public ref int GetReference()
{
return ref _privateField;
}
public override string ToString()
{
return _privateField.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField = 100;
Console.WriteLine(foo);
}
}
Prior to that, you'd have to store the value in a field contained in an object, and pass around a reference to the object instead.
In this example I change the value from 0 to 100 from outside Foo, even though it is stored (indirectly) in a field that is private inside the Foo instance.
class ValueTypeReference<T> where T : struct
{
public T Value { get; set; }
}
class Foo
{
private ValueTypeReference<int> _privateField = new ValueTypeReference<int>{ Value = 0 };
public ValueTypeReference<int> GetReference()
{
return _privateField;
}
public override string ToString()
{
return _privateField.Value.ToString();
}
}
public class Program
{
public static void Main()
{
var foo = new Foo();
var referenceToPrivateField = foo.GetReference();
referenceToPrivateField.Value = 100;
Console.WriteLine(foo);
}
}
Output:
100
Well, if I udnerstood you correctly, you want the variable to have global scope, which can be achieved by putting variable as class field/property:
class Program
{
private static int _i;
static void Main()
{
_i = 0;
Add(100);
// now _i == 100
}
static void Add(int increment)
{
_i += 100;
}
}

CS5001 Program does not contain a static 'Main' method suitable for an entry point

I am new to C#. I'd be thankful if any body can show me why the following error is shown for code.
"CS5001 Program does not contain a static 'Main' method suitable for an entry point"
using System;
class test
{
void Foo(int x) { Console.WriteLine(x); }
void Foo(double x) { Console.WriteLine(x); }
void Foo(int x, float y) { Console.WriteLine(x); Console.WriteLine(y);}
void Foo(float x, int y) { Console.WriteLine(x); Console.WriteLine(y); }
void Main()
{
Foo(123); // int
Foo(123.0); // double
Foo(123, 123F); // int, float
Foo(123F, 123); // float, int
}
}
This error occurs when Main method is defined with incorrect signature. This error also occurs if Main, is defined with the wrong case, such as lower-case main.
Main must be declared as static and it must return void or int, and it
must have either no parameters or else one parameter of type string[]
Define your main method like this -
static void Main()
OR like this -
static void Main(string[] args)
Have a look at this link for more information
Your fixed code should look like this:
using System;
class test
{
static void Foo(int x) { Console.WriteLine(x); }
static void Foo(double x) { Console.WriteLine(x); }
static void Foo(int x, float y) { Console.WriteLine(x); Console.WriteLine(y); }
static void Foo(float x, int y) { Console.WriteLine(x); Console.WriteLine(y); }
static void Main()
{
Foo(123); // int
Foo(123.0); // double
Foo(123, 123F); // int, float
Foo(123F, 123); // float, int
}
}
Remove <OutputType>Exe</OutputType> in project file (.csproj)

Can't convert from void to bool compile error

I am having some trouble with visual studio, as it says it won't compile. I can't figure out what the problem is. it says something like it can't convert from void to bool, even though there is no 'bool'. Here is my code:
using System;
namespace ConsoleApplication14
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(myFunction(14));
}
public static void myFunction(int x)
{
return x + 2;
}
}
What is causing that compile error?
try this
class Program
{
static void Main(string[] args)
{
Console.WriteLine(myFunction(14));
}
public static int myFunction(int x)
{
return x + 2;
}
}
You are returning an Int. Void has no return type. To make this work you will need
public static int myFunction(int x)
{
return x + 2;
}
The type void indicates that a mamber does not return anything. So when your method is marked as such it should not return a value. However when you call Console.WriteLine you need a value to be printed to the console.
Furthermore your method should make a calculation and return something - in your case an int. So instead of defining your method as void let it return an int:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(myFunction(14));
}
public static int myFunction(int x)
{
return x + 2;
}
}
In your myfunction method your returning some int value but myfunction return type is void in your code. Plaese change void to int and the application will work.
namespace ConsoleApplication1
{
class Program
{
public static int myFunction(int x)
{
return x + 2;
}
static void Main(string[] args)
{
Console.WriteLine(myFunction(14));
Console.ReadLine();
}
}
}

Categories

Resources