I am trying to understand closures, already read some materials but.. then i tried this.
As far as i understand, a class is generated containing the specific anonymous method (in my case, the one writing to the console) and the int variable j. How does it store all the j values in only one class? Are there many instances of this kind of class generated behind the scenes?
class Program
{
public static List<Action> actions = new List<Action>();
static void Main(string[] args)
{
AddActions(10);
actions[0]();
actions[1]();
Console.ReadLine();
}
public static void AddActions(int count)
{
for (int i = 0; i < count; i++)
{
int j = i;
actions.Add(delegate()
{
Console.Write("{0} ", j);
});
}
}
}
with result: 0 1
Here is your code decompiled into classes rather than lambdas.
private class Program
{
public static List<Action> actions;
static Program()
{
Program.actions = new List<Action>();
}
private static void Main(string[] args)
{
Program.AddActions(10);
Program.actions[0]();
Program.actions[1]();
Console.ReadLine();
}
public static void AddActions(int count)
{
for (int index = 0; index < count; ++index)
{
Program.\u003C\u003Ec__DisplayClass2_0 cDisplayClass20 = new Program.\u003C\u003Ec__DisplayClass2_0();
cDisplayClass20.j = index;
Program.actions.Add(new Action((object)cDisplayClass20, __methodptr(\u003CAddActions\u003Eb__0)));
}
}
private sealed class \u003C\u003Ec__DisplayClass2_0
{
public int j;
public \u003C\u003Ec__DisplayClass2_0()
{
base.\u002Ector();
}
internal void \u003CAddActions\u003Eb__0()
{
Console.Write("{0} ", (object)this.j);
}
}
}
As you can see, for example iteration of the loop you get a new instance of new Program.\u003C\u003Ec__DisplayClass2_0();.
Yes, many instances are generated.
You need an the extra variable j in the scope of the loop body because the variable i has a scope of the method's body, and only a single closure object would be generated for it.
void Main()
{
AddActions(10);
var closure1 = functions[0]();
var closure2 = functions[1]();
Console.WriteLine(object.ReferenceEquals(closure1, closure2));
// False
}
public static void AddActions(int count)
{
for (int i = 0; i < count; i++)
{
int j = i;
functions.Add(delegate()
{
Console.WriteLine(j);
Expression<Func<int>> exp = () => j;
Console.WriteLine(exp.ToString());
var m = (MemberExpression)exp.Body;
var c = (ConstantExpression)m.Expression;
Console.WriteLine(c.Value.ToString());
return c.Value;
});
}
}
public static List<Func<object>> functions = new List<Func<object>>();
Result
0
() => value(UserQuery+<>c__DisplayClass1_0).j
UserQuery+<>c__DisplayClass1_0
1
() => value(UserQuery+<>c__DisplayClass1_0).j
UserQuery+<>c__DisplayClass1_0
False
Related
One of my common Class methods generates a list of parameters and I want to set each of them consistently as a parameter to my NUnit test.
I read some documentation about TestCaseSource attribute but can't figure out how to implement it.
For example my method return a list with
"1","2","3","4"
...inside how do I put each of them into my test. Thanks!
Here is my method that return a list:
public static List<string> TestCombinationsProvider()
{
List<string> resultList = new List<string>();
List<string> parametersList = new List<string>();
foreach (var item in ReturnDynamicPararmetersEntityProperties())
{
parametersList.Add(item.Name);
}
for (int i = 0; i < parametersList.Count; i++)
{
for (int j = i + 1; j < parametersList.Count; j++)
{
resultList.Add(parametersList[i] + " AND " + parametersList[j]);
}
}
return resultList;
}
And empty Nunit test:
[Test]
[TestCaseSource("")]
public void Test1()
{
}
I want to run my test with each row from my list
TestCaseSourceAttribute constructor has two overloads if you need to set data from another class you should use this constructor.
TestCaseSourceAttribute(Type sourceType, string sourceName);
And it looks like this:
public class TestData {
public static IEnumerable<string> TestCombinationsProvider()
{
var parametersList = ReturnDynamicPararmetersEntityProperties().Select(x => x.Name).ToList();
for (int i = 0; i < parametersList.Count; i++)
{
for (int j = i + 1; j < parametersList.Count; j++)
{
yield return parametersList[i] + " AND " + parametersList[j];
}
}
}
}
public class Tests
{
[TestCaseSource(typeof(TestData), nameof(TestData.TestCombinationsProvider))]
public void Test1(string test)
{
Assert.Pass();
}
}
The docs are pretty clear. Instead of returning a List<string>, you need to return a list of testcases, e.g. by directly using IEnumerable<TestCaseData>:
public static IEnumerable<TestCaseData> TestCombinationsProvider()
{
List<string> resultList = new List<string>();
List<string> parametersList = new List<string>();
foreach (var item in ReturnDynamicPararmetersEntityProperties())
{
parametersList.Add(item.Name);
}
for (int i = 0; i < parametersList.Count; i++)
{
for (int j = i + 1; j < parametersList.Count; j++)
{
yield return new TestCaseData(parametersList[i] + " AND " + parametersList[j]);
}
}
}
There are multiple different signatures for that method, e.g. also returning a collection of object[]. But I won´t recommend them, as you´re losing much of the things you can do with the TestCaseData, e.g. setting each tests Name or also its Description.
Then decorate your actuall test-method:
[Test]
[TestCaseSource(nameof(TestCombinationsProvider))]
public void Test1(string p)
{
}
EDIT: When your TestCombinationsProvider-method is in another class use this instead:
[TestCaseSource(typeof(TheClass), nameof(TheClass.TestCombinationsProvider))]
I am a new to OOP and C#. Here is a small experiment I made:
Using System;
class A
{
public int X { get; set; }
public static A[] a = new A[10];
public static int i = 0;
public A()
{
this.X = -2;
}
public A(int x)
{
this.X = x;
}
public static void Add(A b)
{
if (i < 10) a[i] = b;
i++;
return;
}
public void Reveal()
{
Console.WriteLine(X);
}
public static void Show()
{
for (int j=0; j<=10; ++j)
{
a[j].Reveal();
}
}
}
I tried creating a class that has its instances stored inside, up to 10 objects. When invoke the A.Show() a NullReferenceException is thrown: "Object reference not set to an instance of an object." As I guess, it must be the object a[j] is created, then destroyed immediately. So it give a[j] a null value, hence the result?
*This is my main method:
int val = 0;
while (val != -1)
{
Console.Write("create a new object. new value: ");
val = Console.ReadLine();
A a = new A(val);
A.Add(a);
};
A.Show();
Console.ReadKey();
return;
Please pay attention to the upper bound condition of the loop:
for (int j=0; j<=10; ++j)
{
a[j].Reveal();
}
array a has 10 items assigned,but this code shows you have 11 items beginning from 0 to 10, so change it to just lower than 10.And also try to compare
So the correct code can be as follows :
public static void Show()
{
for (int j = 0; j < 10; ++j)
{
a[j]?.Reveal();//Or if(a[j] != null)
}
}
and also make amendment to line that reads the input of client,that must be as follow:
val = int.Parse(Console.ReadLine());//If you are sure that the input
is truly convertible to int,or
int.TryParse(Console.ReadLine() , out int value);
if(value != 0)
{
val = value;
A a = new A(val);
A.Add(a);
}
else
{
throw new Exception();
}
You're incrementing i before assigning a[i], so a[0] is null because it will always start initializing a at 1.
Try changing the add method to this:
public static void Add(A b)
{
if (i < 10)
{ //braces are important for readability
a[i] = b;
}
i++;
return;
}
I'm trying to create a CRUD menu that allows me to insert data at an array and also search it by id.
However I'm trying to create a method that allow to check if id exists and after to display the output.
The problem is that the method isn't correct enough for me to display it across other methods, and also at a switch statement. The problem is it repeats two times in row what is the Id you want to check.
Here's the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace menu
{
class Program
{
private static int id = 1;
enum dataInsert { ID, NAME, SURNAME, ADDRES };
static void Main(string[] args)
{
string[,] matrix = new string[10, 4];
insertData(matrix);
searchId(matrix);
visualizeByid(matrix);
}
static int generateId()
{
return id++;
}
static void insertData(string[,] matrix)
{
int n = generateId();
for (int j = 1; j < matrix.GetLength(1); j++)
{
matrix[n - 1, 0] = Convert.ToString(n);
Console.Write($"Insert {Enum.GetName(typeof(dataInsert), j)}: ");
matrix[n - 1, j] = Console.ReadLine();
}
}
static int searchId(string[,] matrix)
{
int choosenId, index = -1;
do
{
Console.Write("Insert Id to visualize: ");
} while (!int.TryParse(Console.ReadLine(), out choosenId));
for (int i = 0; i < matrix.GetLength(0); i++)
{
if (Convert.ToString(choosenId) == matrix[i, 0])
{
index = i;
}
}
return index;
}
static void visualizeByid(string[,] matrix)
{
int pos = searchId(matrix);
for (int i = pos; i < pos + 1; i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
Console.Write($"{matrix[i, j]}\t");
}
Console.WriteLine();
}
}
}
}
The reason "Insert Id to visualize: " is displayed twice is because your program is calling static int searchId(string[,] matrix) twice in a row:
In Main
static void Main(string[] args)
{
string[,] matrix = new string[10, 4];
insertData(matrix);
searchId(matrix); //Here
visualizeByid(matrix); //Called immediately after
}
And visualizeByid
static void visualizeByid(string[,] matrix)
{
int pos = searchId(matrix); //Here
...
}
You should be able to get your expected result by removing the call to searchId from Main.
Unless I'm misunderstanding, it looks like you have an array of objects. Even if those are simply a name and id.
public class Obj
{
public int Id { get; set; }
public string Name { get; set; }
}
Then you have an array, although you could also use a list.
List<Obj> Objects = new List<Obj>();
To check the list/array by Id you can simply use Linq
if (Objects.Where(o => o.Id == IdToCheck).Count() == 0)
{
//Insert new object
Objects.Add(NewObject);
}
I`m trying to find the first fib number to contain 1000 digits. Because i have no data-type capeable of holding such a number, i created a class called hugeNumber which holds the digits in a list, with a decimal base. I get a stack overflow at the generation of the list for the "hugenum" class - I am not sure why (is it really not the right way to do it? Is there a better way?)
Here's my code:
class hugeNum
{
List<int> digits = new List<int>();
public hugeNum(int basic)
{
digits.Add(basic);
}
public hugeNum()
{
}
public static hugeNum operator +(hugeNum first, hugeNum second)
{
hugeNum generated = new hugeNum();
hugeNum finalIter = null;
int carry = 0;
int i = 0;
for (i = 0; i<second.digits.Count && i<first.digits.Count; i++)
{
generated.digits.Add(first.digits[i] + second.digits[i] + carry);
if (generated.digits[i] >= 10)
{
carry = 1;
generated.digits[i] -= 10;
}
else
carry = 0;
}
finalIter = first;
if (i==first.digits.Count)
{
finalIter = second;
}
while (i<finalIter.digits.Count)
{
generated.digits.Add(finalIter.digits[i]);
i++;
}
return generated;
}
public int amountOfDigits()
{
return this.digits.Count;
}
}
class Program
{
public static int fibHugesUntilIter(hugeNum huge1, hugeNum huge2, int reqDigits, int iter)
{
if (huge2.amountOfDigits() == reqDigits)
return iter;
return fibHugesUntilIter(huge2, huge1 + huge2, reqDigits, iter + 1);
}
static void Main(string[] args)
{
Console.WriteLine(fibHugesUntilIter(new hugeNum(1), new hugeNum(1), 1000, 1));
}
}
You can use BigInteger without recursion:
public static int FibHugesUntil(BigInteger huge1, BigInteger huge2, int reqDigits)
{
int number = 1;
while (huge2.ToString().Length < reqDigits)
{
var huge3 = huge1 + huge2;
huge1 = huge2;
huge2 = huge3;
number++;
}
return number;
}
static void Main(string[] args)
{
Console.WriteLine(FibHugesUntil(BigInteger.Zero, BigInteger.One, 1000));
}
Answer: 4782
I'm trying to find the "Median","Maximum","Minimum","Average","Sum of numbers" and if there is any duplicates in the array. I ran into issues in the beginning when I made my methods and tried calling them in the main method. This produced "An object reference is required to access non-static member" so to combat this I made all the variables public static. Wasn't the best option but it worked. So I tackled the rest and when tried to display that I have duplicates I get "not all code paths return a value" So any help on how to fix this and any way to clean up the code will very helpful.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
public class Test
{
public static int maxNum;
public static int minNum;
public static double avgNum;
public static long sumNum;
public static double median;
public static int MaxNum(int[] randArray)
{
maxNum = randArray.Max();
Console.WriteLine("This is the maximum value: " + maxNum);
return maxNum;
}
public static int MinNum(int[] randArray)
{
minNum = randArray.Min();
Console.WriteLine("This is the minimum value: " + minNum);
return minNum;
}
public static long SumNum(int[] randArray)
{
for(int x =0; x < randArray.Length;x++)
sumNum = sumNum +randArray[x];
Console.WriteLine("This is the sum of values: " + sumNum);
return sumNum;
}
public static double Average(int[] randArray)
{
avgNum = randArray.Average();
Console.WriteLine("This is the average of the values: " + avgNum);
return avgNum;
}
public static int GetMedian(int[] randArray)
{
int size = randArray.Length;
int mid = size / 2;
double median = (size % 2 != 0) ? (double)randArray[mid] : ((double)randArray[mid] + (double)randArray[mid - 1]) / 2;
Console.WriteLine("This is the median value:" + median);
return Convert.ToInt32((median));
}
public static bool ContainDups(int[] randArray)
{
for (int i = 0; i < randArray.Length; i++)
{
for (int j = i + 1; j < randArray.Length; j++)
{
if (randArray [i] == randArray [j])
return true;
}
}
return false;
}
public static int ShowDups(int[] randArray)
{
if(ContainDups(randArray) == true)
{
Console.WriteLine("Contains duplicate numbers");
}
else
{
Console.WriteLine("No duplicate numbers");
}
}
public static void Main()
{
int[] randArray = new int[1000];
Random r = new Random();
for(int i = 0; i < randArray.Length; i++)
{
randArray[i] = r.Next();
}
Array.Sort(randArray);
for (int i = 0; i < 1000; i++)
{
// Console.WriteLine(","+randArray[i]);
}
MaxNum(randArray);
MinNum(randArray);
SumNum(randArray);
Average(randArray);
GetMedian(randArray);
ContainDups(randArray);
ShowDups(randArray);
}
}
This method public static int ShowDups(int[] randArray) doesn't return anything. You just write to te console a message and you don't return an int as it is expected by the signature of your method.
First if all the class members are static, just make the class to be static instead .
Secondly, if you have no intention to return value in your function and just write to console, then use void instead of int