Passing list members into a function - c#

How would I pass a list of values into a function, where the values are already stored in a list and the function isn't the same every time?
To explain, I've got a list of several different types of custom objects (A List<object> to make this work) and I want to pass those objects into a function. However, the function isn't always the same. I could have several different functions, and, assuming that List's contents will always match the function's input variables, I want to be able to pass the list's contents into my function.
The following code is an example of what might work, but for one flaw:
List<object> myListOfVariables = new List<object>();
myListOfVariables.Add("Hello, world!");
myListOfVariables.Add(10);
void SayHelloXTimes(string helloString, int x) {
for(int i = 0;i<x;i++) {
print(helloString)
}
}
SayHelloXTimes(myListOfVariables[0], myListOfVariables[1]);
Now, since I know my list will always contain the right amount of variables in the right positions, that would work, if I only had one function. But the problem is, I need to expand this so I could take apart my list and pass it into functions with different amounts of parameters.
For other reasons, I know my list will always have the right amount of variables in the right positions, so we don't need to worry about that. I'll also know the name of the function I need to pass my values into. I suppose I could do a load of if statements depending on the length of my list, like this:
if (myListOfVariables.Length == 2) {
SayHelloXTimes(myListOfVariables[0], myListOfVariables[1]);
}
else if (myListOfVariables.Length == 3) {
SayHelloXTimesForY(myListOfVariables[0], myListOfVariables[1], myListOfVariables[2]);
}
However, this (obviously) is really clunky code and I'd like to avoid it at all costs. Is there another solution to my problem? I know this is really confusing, but I did my best to explain it. If you're still confused as to what I'm trying to do, please let me know.
And no, this is not a homework problem. ;)

I think want you want to do can be done using reflection. Look at MethodBase.Invoke Method
All you have to do is add all the parameters in the order the function expects to an object array.
class Program
{
public static void SayHelloXTimes(string helloString, int x)
{
for (int i = 0; i < x; i++)
{
Console.WriteLine(helloString);
}
}
static void Main(string[] args)
{
MethodInfo Method = typeof(Program).GetMethod("SayHelloXTimes");
Method.Invoke(null, new object[] { "foo", 3 });
Console.ReadLine();
}
}

You want params:
void SayHelloXTimes(params string[] list) {
for(int i = 0;i<list.Length;i++) {
print(list[i])
}
}
SayHelloXTimes("Hi", "Hi", "Hi"); // legal
SayHelloXTimes("Hi"); // legal
SayHelloXTimes("Hi", "Hi", "Hi", "Hi", "Hi", "Hi"); // still legal

If this were my application, I would create a parameter class to hold the list values.
You could pass the list into the class' constructor and either extract it into class-local properties (since you know the positions) or you could expose the values as readonly property directly from the list.
You can then just pass an instance of the parameter class to each of the methods and not have to worry about the number of parameters to the methods.

Related

Contains method using Linq/Lambda

This method finds different dates and adds to dates array. Is it possible to make this method with linq/lambda?
public static void FindDates(DateTime[] dates, LinkedList<Letter> L, out int counter)
{
counter = 0;
foreach (var let in L)
{
if (!dates.Contains(let.Date))
{
dates[counter] = let.Date;
counter++;
}
}
}
You need to change the prototype of the method, but you can do something like:
public static IReadOnlyList<DateTime> FindDates(IEnumerable<Letter> L)
{
return L.Select(l => l.Date).Distinct().ToList();
}
The value of counter can be retrieved easily by reading the Count property of the result list.
Overall, it's a good practice to avoid side-effects in methods as much as possible. Modifying an array passed as a parameter like you do is a good way to get bitten later.
Also, since the Linq extension methods are defined on IEnumerable<T>, we can change the parameter of the method to IEnumerable<Letter>. It'll work exactly the same with your LinkedList<Letter>, with the added benefit that it won't break if later you decide to use another collection type (such as List<Letter>)

How do I refresh an array full of returned values of method calls?

In C#, I have a string array that I have written full full of "getter" method calls. They call methods in another class so that the array is populated with the needed strings. It looks something like this:
string[] mCalls = {c.get1(), c.get2(), c.get3()};
I'm sure this situation could apply to any program. However, in my program the variables these methods return are initially set with the string "Unchecked" - thus filling this example array with Unchecked 3 times. As my program goes on and things are checked, the values of the string variables get changed within the class they're in. I've been simply re-calling the getter methods at appropriate times to change what's in my array, like this:
mCalls[0] = c.get1();
mCalls[1] = c.get2();
mCalls[2] = c.get3();
I don't really like this. It seems inevitable that one day I'll have to change something, and if that happens I will have to manually do the tedious work of changing all of the indexing throughout my program. If this happens to be the best way I'm fine with that, but I assume there are better ways. So, in any case, is there a way to "refresh" the values in an array that is set up like this? And if so, what is it?
You want something like this:
public string[] MCalls
{
get
{
return new string[]{c.get1(), c.get2(), c.get3()};
}
private set;
}
and then use MCalls as if it is a regular variable whenever you want to access the arrays
You could change your array to contain functions instead of strings like this:
Func<string>[] mCalls = { c.get1, c.get2, c.get3...};
And then use it this way:
string c2 = mCalls[1]();
But note that this way every access is a method call. I'm not sure what you are really trying to achieve, there may be better overall designs than this approach.
Couple of options:
Create an array of lambdas:
var mCalls = new Func<object, string>[] {
(object o) => o.ToString() ,
(object o) => o.GetHashCode().ToString(),
(object o) => o.GetType().ToString(),
};
If the input to each lambda is the same you can create a lambda that returns an array:
Func<object, string[]> GetValues = (object o) => new string[]
{
o.ToString() ,
o.GetHashCode().ToString(),
o.GetType().ToString(),
};
Then just reload the array by calling the lambda:
mCalls = GetValues(c);
Note that it isn't technically refreshing the array, it's creating a new array. If you need to keep the array the same but just update the values you'd ned to loop through the array and assign the values by index.
What you could do is loop thorugh with reflection and get all methods from the class and from here you can get a list of method names. With this list you can assign to an array or run the methods by name or whatever. You can also filter the list to get your specific method names only:
var methodNames = typeof(MyClass).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Select(x => x.Name)
.Distinct()
.OrderBy(x => x);
To call the methods:
foreach(var method in methodNames)
{
typeof(MyClass).GetMethod(method).Invoke(t, new[] { "world" });
}

Retrieving Anonymous Object's Property in C#

I have the following code
using System;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
List<object> list = new List<object>();
list.Add(new {
Value = 0
});
//Console.WriteLine(list[0].Value);
}
}
Is there a simple way to write the commented line of code without causing a compile time error? I know I could resort to using the dynamic keyword or implementing an extension method for the Object class that uses Reflection, but is there maybe another more acceptable way?
The goal is the avoid creating a class since its only purpose would be to store data. But at the same time still be able to retrieve the data later on in the program. This code will eventually end up in a web method which is why I want it to be dynamic / anonymous in the first place. All of the objects would end up having the same properties, as they would be storing values stored in tables, but the values are needed later for other calculations.
Is there a simple way to write the commented line of code without causing a compile time error?
Not with the way you've declared the list. If your list will contain only objects of that anonymous type, you could use an array initializer and convert it to a List<{anonymous type}>:
var list = (new [] {
new { Value = 0 }
}).ToList();
Console.WriteLine(list[0].Value);
The nice thing is that you can add to the list easily, since anonymous types with the same properties are merged into one type by the compiler:
list.Add(new {Value = 1});
Per Servy's comment, a method to avoid an array creation would just be:
public static List<T> CreateList<T>(params T[] items)
{
return new List<T>(items);
}
usage:
var list = CreateList(new { Value = 0 });

Programmatical naming variable c#

I have a large amount of nested foreach loops and I'm running out of variable names to use...
Could I do something like this :
//int i = 1
string "number"+i = new String("FirstElement");
I've seen some posts about this for languages such as C and javascript, but I don't know how to do it in C#.
In case you can't name variables after other variables : how could this problem otherwise be solved?
This problem could otherwise be solved by using meaningful variable names - running out of names would mean running out of concepts for what the thing is trying to achieve, which is hard to believe.
If your requirement is to work with a collection of variables, then put them in a collection; if it's to have n number of variables all strictly defined by name, then name them explicitly, and so on.
var a = new List<int>();
for(int i=0;i<100;i++)
{
a.Add(i);
}
Console.WriteLine(a[0]);
Console.WriteLine(a[1]);
etc....
This way you make list which contains 100 elements, you can access them by nameoflist[index]
A while back I asked a similar question:
Python - neat way of creating multiple objects?
Basically, if you have lots of very similar variables named things like variable_1, variable_2, etc, then thats normally a sign that you should be using an array or list of variables instead.
So instead of 10 separate string variables, create a list (or array) of strings.
The way you are doing will not work in C#. You can not create variables at run time. If you want
you have to use a list to store your variable name and value. Therefore you better create a class to hold name of the variable and value.
class Variable
{
string Name;
string Value;
}
Now create another class to hold variables
class VaraibleHolder
{
List<Variable> Variables;
VariableHolder()
{
Variables = new List<Variables>();
}
public void Add(Variable Vbl)
{
Variable vbl = Variables.SingleOrDefault(v=>v.Name == Vbl.Name);
if(vbl == null)
{
Variables.Add(vbl);
}
}
public void Remove(string VblName)
{
//this is a lamda expression.
Variable vbl = Variables.SingleOrDefault(v=>v.Name == VblName);
if(vbl != null)
{
Variables.Remove(vbl);
}
}
public Variable GetVariable(string VblName)
{
Variable vbl = Variables.SingleOrDefault(v=>v.Name == VblName);
return vbl;
}
}
So you can use Variable holder to create and store varaibles at runtime. Hope this will help you.

Simple way to transpose data before passing to functions?

This is one of the hardest questions I've ever had to title here on SO. :) Although the title might not make sense, hopefully the question itself will.
Let's say I have a data structure like a Dictionary<string, List<double>>, and that I have functions that then take List<double>s as a parameter:
Dictionary<string, List<double>> candy_positions = new Dictionary<string, List<double>>();
candy_positions.Add( "Godiva", new List<double> { 1.0, 2.0, 4.0 });
EatCandy( candy_positions["Godiva"]);
...
But now I have decided that I don't want to do it this way. I want to replace my Dictionary with a List<CandyPositions>, where CandyPositions looks something like this:
public class CandyPositions
{
public double Sees;
public double Godiva;
public double Lindt;
}
However, I really would like to leave EatCandy() alone. Obviously, the problem is now that my data doesn't lend itself to be passed directly into the method. Instead, I have to do something lame like:
List<CandyPositions> candy_positions = new List<CandyPositions>();
...
var positions = from x in candy_positions select x.Godiva;
EatCandy( positions.ToList());
every time I want to call the method. I'd prefer to be able to do this in a more simple way, like:
EatCandy( candy_positions.GetPositionsFor( "Godiva"));
where the parameter "Godiva" matches the property name in the CandyPositions class.
After writing this question, I've realized that it isn't really about transposing data -- that part of it can be handled by writing an extension method. The part I don't know how to do is to pass in a property name, so that the extension method can take this and associate it with a class's property. I don't want to pass in a string, either, mainly because this will open the door for all sorts of runtime errors. I know how to make this work by passing "Godiva" to my extension method. What I really want to pass in is something akin to CandyPositions.Godiva instead.
This question is probably a little confusing, so in summary, I would accept the best of two types of answers:
Is there a better way to deal with transposing data, than to use an extension method + some way of accessing a property name?
Is there a way to specify the property that I want my extension method to retrieve, other than by a string?
My current extension method looks like this:
public static List<double> GetPositions( this List<CandyPositions> positions, string candy_name)
{
return (from x in positions select x.GetType().GetProperty(candy_name).GetValue(x, null)).Cast<double>().ToList();
}
Well, you could use:
public static List<double> GetPositions(this List<CandyPositions> positions,
Func<CandyPositions, double> projection)
{
return positions.Select(projection).ToList();
}
and call it with:
EatCandy(candyPositions.GetPositions(x => x.Godiva));
On the other hand, if you can change EatCandy to accept an IEnumerable<double> instead, you don't need the extra method - you can just use:
EatCandy(candyPositions.Select(x => x.Godiva));
without writing an extra method at all.
EDIT: If you need to iterate over two sequences at once, there are two options:
If you're using .NET 4, you can use the Zip extension method.
Otherwise, you can basically write your own:
using (var iterator1 = sequence1.GetEnumerator())
using (var iterator2 = sequence2.GetEnumerator())
{
while (iterator1.MoveNext() && iterator2.MoveNext())
{
var value1 = iterator1.Current;
var value2 = iterator2.Current;
// Use the values here
}
}

Categories