How can we get parameter name called by a method in C#?
Example:
public static void PrintList (List<string> list)
{
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
PrintList(oxygenList);
I need the method to print:
oxygenList
Thanks.
If you're using C# 10 or later, you can use the new CallerArgumentExpression attribute to achieve this:
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public static class Program
{
public static void Main()
{
List<string> oxygenList = new List<string> { "A", "B", "C" };
PrintList(oxygenList);
}
public static void PrintList(List<string> list, [CallerArgumentExpression("list")] string? name = null)
{
Console.WriteLine("Argument name = " + name); // Prints "Argument name = oxygenList
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
}
However, note that this gives the expression used when calling the method - so if you call it with this code:
public static void Main()
{
PrintList(getOxygenList());
}
public static List<string> getOxygenList()
{
return new List<string> { "A", "B", "C" };
}
the value passed as name will be "getOxygenList()".
It has to work like this because an expression can be used for the parameter - it's not restricted to a simple variable name.
You should use:
Console.WriteLine(nameof(list));
See more: nameof
Update:
This is still not clear for me what do You want to achieve but the easiest way would be:
public static void PrintList (List<string> list, string nameOfList)
{
Console.WriteLine(nameOfList);
Console.WriteLine("\n");
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("\n");
}
PrintList(oxygenList, nameof(oxygenList));
You may also create a bit cleaner extension method, like this:
public static class ListPrinter
{
public static void PrintListWithName(this List<string> list, string nameOfList)
{
Console.WriteLine(nameOfList);
list.ForEach(element => Console.WriteLine(element));
}
}
called like this:
oxygenList.PrintListWithName(nameof(oxygenList));
I have a list of string values. I iterate this list with a foreach. I apply on every list item Assert.That() method. Now comes the twist: I give as a second parameter of the method a function that returns IResolveConstraint. When the function returns Has.Exactly(1).Contains(), then AT THE SECOND item of the list (second iteration of the foreach) the assertion evaluates (throws) this message: "Expected: collection containing "value"". But the assertion was supposed to pass, because it was verifying exactly one item, not a collection.
I had NUnit 3.2.1. I upgraded to version 3.12.0 and after that the message changed from : "Expected: collection containing "value"" to message: "Expected: some item equal to "value"" and assertion still didn' pass.
public class Verifiers
{
public void VerifyCollectedValues(List<string> collectedValues, List<string> expectedValues
, string collectedValuesFrom, int countOfValueExpactance, bool verifyExactSameValue = true)
{
// Create a constraint function
Func<string, IResolveConstraint> constraintFunction = CreateConstraintFunction(Has.Exactly(countOfValueExpactance), verifyExactSameValue);
// Pass the constraint to the method
VerifyCollectedValues(constraintFunction, collectedValues, expectedValues, collectedValuesFrom);
}
public void VerifyCollectedValues(Func<string, IResolveConstraint> constraintFunction, List<string> collectedValues, List<string> expectedValues
, string collectedValuesFrom)
{
foreach (string expectedValue in expectedValues)
{
// Apply the constraint
Assert.That(collectedValues, constraintFunction(expectedValue));
}
}
public Func<string, IResolveConstraint> CreateConstraintFunction(ConstraintExpression constraintExpression, bool verifyExactSameValue)
{
if (verifyExactSameValue)
{
return (string value) => constraintExpression.EqualTo(value);
}
else
{
return (string value) => constraintExpression.Contains(value);
}
}
}
Sample code:
Verifiers verifiers = new Verifiers();
List<string> expectedValues = new List<string>()
{
"value1",
"value2",
"value3",
};
var collectedValues = new List<string>()
{
"some_value0",
"some_value1",
"some_value2",
"some_value3",
};
// This passes
foreach(string expectedValue in expectedValues)
{
Assert.That(collectedValues, Has.Exactly(1).Contains(expectedValue));
}
// This fails with the message: "Expected: collection containing "value2"" (with NUnit v3.2.1) / "Expected: some item equal to "value2""(with NUnit v3.12.0)
verifiers.VerifyCollectedValues(collectedValues, expectedValues, 1, false);
My assumption is that IResolveConstraint is causing the problem. What I don't understand is why the first item of list passes but the second one doesn't.
I'll be grateful for any answer.
UPDATE:
I've done some edits and base on that I excluded the possibility that IResolveConstraint is causing the problem. Here is sample of the current code:
public class Verifiers
{
public void VerifyCollectedValues(List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom, int countOfValueExpectance, bool verifyExactSameValue = true)
{
VerifyCollectedValues(CreateConstraintExpressionExactly(countOfValueExpectance), collectedValues, expectedValues, collectedValuesFrom, verifyExactSameValue);
}
private void VerifyCollectedValues(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom, bool exactSameValue)
{
if (exactSameValue)
{
VerifyCollectedValuesEqualTo(constraintExpression, collectedValues, expectedValues, collectedValuesFrom);
}
else
{
VerifyCollectedValuesContains(constraintExpression, collectedValues, expectedValues, collectedValuesFrom);
}
}
private void VerifyCollectedValuesEqualTo(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom)
{
Func<string, EqualConstraint> constraintFunction = (string value) => constraintExpression.EqualTo(value);
foreach (string expectedValue in expectedValues)
{
Assert.That(collectedValues, constraintFunction(expectedValue));
}
}
private void VerifyCollectedValuesContains(ConstraintExpression constraintExpression, List<string> collectedValues, List<string> expectedValues, string collectedValuesFrom)
{
// if I don't use constraintExpression but write the expression manually (Has.Exactly(1).Contains(value)), then it works just fine
Func<string, ContainsConstraint> constraintFunction = (string value) => constraintExpression.Contains(value);
foreach (string expectedValue in expectedValues)
{
Assert.That(collectedValues, constraintFunction(expectedValue));
}
}
private ConstraintExpression CreateConstraintExpressionExactly(int countOfExpectance)
{
return Has.Exactly(countOfExpectance);
}
var verifiers = new Verifiers();
List<string> expectedValues = new List<string>()
{
"value1",
"value2",
"value3",
};
var collectedValues = new List<string>()
{
"some_value0",
"some_value1",
"some_value2",
"some_value3",
};
// This one pass successfully
foreach(string expectedValue in expectedValues)
{
Assert.That(collectedValues, Has.Exactly(1).Contains(expectedValue));
}
// But this one still doesn't pass and fails at the second list item "value2"
verifiers.VerifyCollectedValues(collectedValues, expectedValues, "list of strings", 1, false);
Your assumption that Has.Exactly(1).EqualTo() will pass if the actual value is a non-collection is not correct. ExactCountConstraint will error (not quite the same as fail) if passed a non-collection type.
However, in this case, string is a collection of chars so it tries to run.
The problem is that you are using a collection constraint, which iterates the list, but you are also iterating it yourself. You should either do it all yourself (which seems silly) or rely on the ExactCountConstraint to do the work.
If you continue to iterate the list yourself, then you should not use any collection constraints. In the example case, you would simply use Is.EqualTo().
Well, the bug is in your implementation actually, since you're passing ConstraintExpression all the time.
If you try to decompose the working code and create methods for each verification you'll have something like this:
[Test]
public void ListCompareTest()
{
List<string> expectedValues = new List<string>()
{
"value1",
"value2",
"value3",
};
var collectedValues = new List<string>()
{
"some_value0",
"some_value1",
"some_value2",
"some_value3",
};
int count = 1;
// This one pass successfully
foreach (string expectedValue in expectedValues)
{
ItemsConstraintExpression itemsConstraintExpression = GetExactly(count);
// this code works
Assert.That(collectedValues, GetContains(expectedValue, itemsConstraintExpression));
}
// this code works as well
DoVerification(expectedValues, collectedValues, 1, false);
}
public static void DoVerification(List<string> expectedList, List<string> actualList, int exactlyCount, bool equalsOrContains)
{
if (equalsOrContains)
{
foreach (var expectedValue in expectedList)
{
Assert.That(actualList, GetEquals(expectedValue, GetExactly(exactlyCount)));
}
}
else
{
foreach (var expectedValue in expectedList)
{
Assert.That(actualList, GetContains(expectedValue, GetExactly(exactlyCount)));
}
}
}
private static EqualConstraint GetEquals(string expectedValue, ItemsConstraintExpression itemsConstraintExpression)
{
return itemsConstraintExpression.EqualTo(expectedValue);
}
private static ContainsConstraint GetContains(string expectedValue, ItemsConstraintExpression itemsConstraintExpression)
{
return itemsConstraintExpression.Contains(expectedValue);
}
private static ItemsConstraintExpression GetExactly(int count)
{
return Has.Exactly(count);
}
namespace ConsoleApplication4
{
class T1
{
public int MyProperty { get; set; }
}
class Program
{
static void Main(string[] args)
{
var tmp = (new[] { 1, 3, 4 }).Select(x =>new T1 { MyProperty=x});
foreach (var s in tmp)
{
s.MyProperty = 9;
}
foreach (var s in tmp)
{
Console.WriteLine(s.MyProperty);
}
Console.ReadLine();
}
}
}
I expect there are three 9 on screen, but the values are still same.
However, if I modify code a little bit, the values would be changed successfully i.e. :
var tmp = (new[] { 1, 3, 4 }).Select(x =>new T1 { MyProperty=x}).ToList();
I wonder why?
The reason is deferred execution.
tmp is not a list or an array. It's only a definition how to create the enumeration. Or in other words: tmp is only the question, but not the answer.
So in the second foreach, the enumerator created by the Select is executed again, creating new instances of T1.
When you use .ToList() instead, the enumeration is converted to a List (so tmp is a List<T1>). And you can iterate that List as often as you want without creating new instances.
I'm getting an
Object reference not set
exception in this Program..
Where I store Output1[k++] there is a problem...
CODE:
Class stringsor
{
public static string[] output1;
public static void sortstrings(string[] input1)
{
int k = 0;
foreach (var item in input1)
{
output1[k++] = (item.OrderBy(i => i)).ToString();
}
Sorting Using Linq
output1 = new string[k];
foreach(var item in output1)
{
Console.WriteLine(item);
}
}
public static void Main(string[] args)
{
string[] input1 = { "Adkad","jor","ioeuo","zkas","aka","nma"};
sortstrings(input1);
}
}
You have declared output1, but not initialized it.
Before you use it in sortStrings, try.
output1 = new string[input1.Length];
problem is you are not initializing output array before using it. Since you already using LINQ you can initialize and assign output array directly like below
public static void sortstrings(string[] input1)
{
output1 = input1.Select(word => new string(word.OrderBy(i => i).ToArray())).ToArray();
foreach (var item in output1)
{
Console.WriteLine(item);
}
}
I want to sort the string array.
But what you currently doing is reversing the order of characters in the output array. it is not sort the string array. is that what you expect? if you need to order the strings you can so as below
output1 = input1.OrderBy(word => word).ToArray();
public class Stock
{
}
class Program
{
static void Main(string[] args)
{
ObjectCache cache = MemoryCache.Default;
cache["test"] = new Stock();
var x = cache.OfType<Stock>().ToList();
}
}
This is returning empty ...I thought OfType is supposed to return all instances in a collection of type T ?
Just to rule out the ObjectCache as a possible culprit I also tried
List<object> lstTest = new List<object>();
lstTest.Add(new Stock());
var y = lstTest.OfType<Stock>().ToList();
This works however - so it seems like the problem is with the ObjectCache, which is an instance of a Dictionary underneath
SOLUTION
cache.Select(item => item.Value).OfType<T>().ToList()
Thanks Alexei!
MemoryChache returns enumerator of KeyValuePair<string,Object>, not just values: MemoryChache.GetEnumerator().
You need to case accordingly to get your items. Something like:
var y = cache.Select(item => item.Value).OfType<Stock>();
This would work
cache.GetValues(new string[] {"test"}).Values.OfType<Order>()
But I don't think you should use this.
Cache works like a Dictionary...so you can get set of KeyValuePairs with GetValues
This worked for me.
public class Stock
{
public Stock()
{
Name = "Erin";
}
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
System.Collections.ArrayList fruits = new System.Collections.ArrayList(4);
fruits.Add("Mango");
fruits.Add("Orange");
fruits.Add("Apple");
fruits.Add(3.0);
fruits.Add("Banana");
fruits.Add(new Stock());
// Apply OfType() to the ArrayList.
var query1 = fruits.OfType<Stock>();
Console.WriteLine("Elements of type 'stock' are:");
foreach (var fruit in query1)
{
Console.WriteLine(fruit);
}
}
}
Remember IEnumerable is lazily evaluated. Use a foreach to loop through query1 and you will see it only find the Stock object.
Yeah. Sorry myself. ObjectCache is a IEnumerable>
Not really an IDictionary.
This works:
var c = cache.Select(o => o.Value).OfType<Stock>().ToList();