Dynamically pass entries to Method requiring params - c#

I'm currently having the following method which requires params - I cannot change this methods definition:
public static DoStuff(params Parameter[] p){ /* ... */ }
I do not know how many parameters I'll have at runtime, so I want to pass an array or a list - I've thought about using Iterators like this:
List<Parameter> pList = new List<Parameter>();
pList.Add(new Parameter("#a", "aaaa!");
pList.Add(new Parameter("#b", "bbbb!");
pList.Add(new Parameter("#c", "cccc!");
DoStuff(Iterate(pList));
And here's the Iterate-Method:
public static IEnumerator<Parameter> Iterate(List<Parameter> pList)
{
foreach (Parameter p in pList)
yield return p;
}
Unfortunately, it does not work, it keeps telling me that it can't cast (generated type) to CommandParameter.
Any help (or different approaches) would be appreciated!
Edit: It appears, in an attempt to simplify my solution for the sake of making my question understandable I trivialized my problem.
In addition to this array, I'd like to also pass "normal" Parameters like this:
DoStuff(Iterate(pList), new Parameter("#d", "dddd!"));
I do this merely out of curiosity to see whether it works - but this does not work simply by casting my List to an Array and appending the next Parameter.
Thanks,
Dennis

You could do it like that:
DoStuff(pList.Concat(new[]{ new Parameter("#d", "dddd!"), new Parameter("#e", "eeee!"}).ToArray());

As far as I know, the params keyword requires an array as parameter type, and you could use DoStuff(pList.ToArray()); then.
The definition you specified though should then be
public static DoStuff(params Parameter[] p){ /* ... */ }
Or have I missed out on some new features?

Out of interest, why do you need to use the Iterate / yield method?
Is there a reason why this would not work?
static void Main(string[] args)
{
List<Parameter> pList = new List<Parameter>();
pList.Add(new Parameter("#a", "aaaa!"));
pList.Add(new Parameter("#b", "bbbb!"));
pList.Add(new Parameter("#c", "cccc!"));
DoStuff(pList.ToArray());
}
static void DoStuff(params Parameter[] parameters){
foreach(var p in parameters)
{
//do something.
}
}

Related

How to loop thru a Generic Class / List

Hi I'm learning Generics thru MSDN here
and I want to do a foreach loop to display data in a console.writeline.
I tried to do the foreach loop as below but it's not working.
// Declare the generic class.
public class GenericList<T>
{
public void Add(T input) { }
}
class TestGenericList
{
private class ExampleClass { }
static void Main()
{
// Declare a list of type int.
GenericList<int> list1 = new GenericList<int>();
list1.Add(150);
// Declare a list of type string.
GenericList<string> list2 = new GenericList<string>();
list2.Add("Toyota");
// Declare a list of type ExampleClass.
GenericList<ExampleClass> list3 = new GenericList<ExampleClass>();
list3.Add(new ExampleClass());
}
}
foreach (GenericList<T> item in list2.ToString().ToList())
{
Console.WriteLine(item); // NOT WORKING !!!!
}
Firstly, by calling the method ToString() on list2, you will get the name of type of your object, because you didn't create your own implementation of method ToString(). So, you are trying to enumerate through letters of string "AppName.GenericList". Unfortunately, letters are of type 'char' and not GenericList.
Secondly, there is no backend behind method Add - items you are 'adding' to your list, in reality aren't added anywhere. Method public void Add(T input) { } does nothing (you should fill the brackets). GenericList at this stage stores no data.
Thirdly, you can't enumerate through your GenericList, because you didn't implement the method GetEnumerator. Only then you will be able to use keyword foreach on objects of your type.
Many of this issues will be solved by the end of the tutorial from link that you provided.

C# collection initializer – is it possible to add an element optionally, based on a condition?

Right now my code looks like this:
var ids = projectId.HasValue ? new List<Guid> { projectId.Value } : new List<Guid>();
Is there a more succinct way of creating a list in one line of code, with one element added optionally?
Another idea for an extension method (the name could definitely be improved, maybe PossiblyCreateSingletonList?):
public static class NullableExtensions
{
public static List<T> SingletonList<T>(this Nullable<T> item) where T : struct
{
return item.HasValue ? new List<T> { item.Value } : new List<T>();
}
}
Usage:
Guid? projectId = null;
List<Guid> projectIds = projectId.SingletonList(); // empty list
I would solve this using a extension method like this:
public static void AddIfNotNull<T>(this List<T> list, T? value) where T : struct
{
if(value != null)
{
list.Add(value.Value);
}
}
Than it could be used like this:
var ids = new List<Guid>();
ids.AddIfNotNull(projectId);
Maybe not as "crafty" (and not a one-liner) as your proposal, but in my opinion it is much easier to read and understand. If desired to be used as a one-liner you could modify the return type of the extension to be the list. That would make it possible to be used something like var ids = new List<Guid>().AddIfNotNull(projectId);
This probably isn't a good idea, but in C# 6, collection initializers also work when Add() is an extension method.
This means you can write the extension Add() like this:
public static void Add<T>(this List<T> list, T? item) where T : struct
{
if (item.HasValue)
{
list.Add(item.Value);
}
}
And then this code will do what you want:
var list = new List<Guid> { projectId };
Note that this will only work for value types (because of the T/T? distinction) and there is no simple way to make it work for reference types.
Also, I would find the line above very surprising, being more succinct is not always better. Which is why I actually wouldn't use this code.
That's pretty succinct, but another option would be to use LINQ:
var ids = new[] { projectId }.Where(x => x.HasValue).Select(x => x.Value).ToList();
If you're going the extension method route, it would have to look something like:
public static void AddIfNotNull<T>(this List<T> list, T? value)
where T : struct
{
if (value.HasValue)
{
list.Add(value.Value);
}
}
You'd have to build a second extension method for reference types (where T : class) if you needed.

How to create a List<long> from a long variable?

how can i convert a long variable into the list?
Code:
long taskId = long.Parse(LocalWorkListVM.ActiveTask.TaskId, CultureInfo.InvariantCulture);
I need to convert it into a List<long> because one of our method expect a list to pass.
So you need a List<long> but you only have a single variable. That's easy, you can use the collection initializer syntax:
List<long> longs = new List<long>{ taskId };
or more verbose with List.Add:
List<long> longs = new List<long>();
longs.Add( taskId );
Try this:
List<long> somelist = new List<long>{long.Parse(LocalWorkListVM.ActiveTask.TaskId, CultureInfo.InvariantCulture)};
This will create a new List and initialise it with the parsed value.
Does it really need to be a List? If there is a way to modify that method to accept an IEnumerable things would get much easier and cleaner (or if IEnumerable is not enough, maybe consider IList).
So considering this, you have a bunch of options.
You can use the Enumerable class' static method Repeat:
Enumerable.Repeat(taskId, 1);
You can write your own extension method:
static class IEnumerableExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this T item)
{
yield return item;
}
}
// and use it as:
taskId.ToEnumerable()
Of course this extension method can be modified to return a List or IList or whatever your exact needs are.
Also, you might create a new overload of the function, which expects a single long instead of the List, somewhere along the lines of this:
public void MyMethod(List<long> list)
{
// Do something
}
public void MyMethod(long item)
{
MyMethod(new List<long>{ item });
}
And finally, there is a nice keyword called params:
public void MyMethod(params long[] items)
{
// call to the previously mentioned extension method
MyMethod(items.ToEnumerable());
}
public void MyMethod(IEnumerable<long> items)
{
// Do stuff
}
This solution has the advantage to work with a single long parameter, comma separated long parameters or with an IEnumerable<long>.

How to specify a list selection method?

I've got a method that computes a list. At certain points in the algorithm a single element from the list needs to be chosen. It doesn't really matter which element is chosen, but I'd like to leave it up to the user to decide.
Right now, I've added an extension method IList<T>.Random() which simply takes a random element. .First() would have worked equally as well. Supposing I want to let the user pick which method is used, or perhaps an entirely different method, how would that look?
I was thinking about using an enum with limited options, and then I could wrap each of these calls in a switch and call the appropriate function. But maybe some sort of lambda function would be more appropriate?
This method needs to be used in two different places, once on a List<char> and once on a List<string>. I want to use the same method for both.
This isn't a GUI app. I'm trying to decide how to design the API.
Specifically, I want to have a field like
public Func<IList<T>, T> SelectElement = list => list.First();
Which would then be used in the method,
public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)
But generic fields aren't possible. So I'm looking for an alternative solution. One would be to make the SelectElement method an argument to Reverse(), then I could make it generic... but I was hoping to keep it at a class-level for re-usability. Don't want to pass any more args to the function if I can help it.
Edit: full source code
how about this:
public class MyClass
{
public static class C<T>
{
public static Func<IList<T>, T> SelectElement;
}
public int Test(IList<int> list)
{
return C<int>.SelectElement(list);
}
}
static class Program
{
static void Main(string[] args)
{
MyClass.C<char>.SelectElement = xs => xs.First();
MyClass.C<int>.SelectElement = xs => xs.First();
var list = new List<int>(new int[] { 1, 2, 3 });
var c = new MyClass();
var v = c.Test(list);
Console.WriteLine(v);
}
}
Here's an extremely basic example I put together using a generic method that takes in a Func<IEnumerable<T>, T> for selecting an item from the list and then returns the result. I've done a few examples of how to call it:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Simple list.
var list = new List<int> { 1, 2, 3, 4 };
// Try it with first
var result = DoItemSelect(list, Enumerable.First);
Console.WriteLine(result);
// Try it with last
result = DoItemSelect(list, Enumerable.Last);
Console.WriteLine(result);
// Try it with ElementAt for the second item (index 1) in the list.
result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
Console.WriteLine(result);
}
public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
{
// You can do whatever you method does here, selector is the user specified func for
// how to select from the enumerable. Here I just return the result of selector directly.
return selector(enumerable);
}
}
}
If you want to limit the choices a user has you could follow the route of an enum and make this method a private method and then have a way to convert the enum to the appropriate selector delegate to pass to the underlying private method.
public Func<IList<object>, object> SelectElement = list => list.First();
private T _S<T>(IEnumerable<T> list)
{
return (T)SelectElement(list.Cast<object>().ToList());
}
I can make the anonymous method work on objects, thereby avoiding generics, and then add a helper method which is what I'll actually use to call it. A little ugly, but seems to work.
This works for chars and strings. Haven't tested with other types. Built this before I saw Ralph's code, which is practically the same.
LINQPad code:
void Main()
{
var chars = new List<char>();
var strings = new List<string>();
chars.AddRange(new char[] {'1','2','4','7','8','3'});
strings.AddRange(new string[] {"01","02","09","12","28","52"});
chars.Dump();
strings.Dump();
Func<IList<object>, string> SelectFirst = ( list )
=> list.First().ToString();
Func<IList<object>, string> SelectLast = ( list )
=> list.Last().ToString();
Func<IList<object>, string> SelectRandom = ( list )
=> list.ElementAt( new Random().Next(0, list.Count())).ToString();
SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump();
}
private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{
return func(list);
}

How do I use a collection to store a delegate?

I wanted to have a hashtable with a string as key and a functionpointer (delegate) as value.
This way calling the correct routine given a string based command.
However, the compiler won't eat it.
What am I doing wrong?
//declaration
public delegate void categoryHandler(String request);
//init code
Hashtable categories = new Hashtable();
categories.Add("campaigns", Campaigns.post);
//function call
String category = "campaigns";
categoryHandler handler = (categoryHandler) categories[category];
if (handler != null)
{
handler(someString);
}
//handler
static public void post(String request)
{
...
}
The error I get is on the line where I put the function in the hashtable:
Error 2 Argument '2': cannot convert from 'method group' to 'object'
I'm hoping it is just some semantic thingy I forgot...
But if this can't be done... is there another way to have some kind of String based jumptable?
The problem is that you're using Hashtable which is weakly typed. The compiler sees the method group (the name of the method you want to convert into a delegate) but doesn't know what delegate type you mean.
If you want to keep using Hashtable, you could do:
categoryHandler handler = Campaigns.post;
categories.Add("campaigns", handler);
or
categories.Add("campaigns", new categoryHandler(Campaigns.post));
In both cases, the method group is being convert to the specific delegate type, so it's okay.
However, a better solution is to use Dictionary<string, categoryHandler> in the first place - always use strongly typed collections where you can sensibly do so (which is almost always). For the sake of convention, it should be CategoryHandler btw - it's the name of a type. Likewise post should be Post.
Then to call it, you'd use:
String category = "campaigns";
CategoryHandler handler;
if (categories.TryGetValue(category, out handler))
{
handler(someString);
}
If you are using .Net 3.5, you can do what I do when I want to eliminate switch statements:
private readonly Dictionary<string, Action<string>> _lookupTable = new Dictionary<string, Action<string>>
{
{"campaigns", post}
{"somethingElse", doSomethingElse}
{"tryIt", val => doSomethingWithVal(val)}
};
then, where I would have a switch statement, I would do this:
_lookupTable["foo"]("bar");
Don't use a hashtable use the Dictionary
Your code will change too.
//declaration
public delegate void categoryHandler(String request);
//init code
Dictionary<string, categoryHandler> categories = new Dictionary<string, categoryHandler> ;
categories.Add("campaigns", Campaigns.post);
//function call
string category = "campaigns";
if (!categories.ContainsKey(category))
{
// Key not there just return
return;
}
categoryHandler handler = categories[category]; // NO need to cast here
if (handler != null)
{
handler(someString);
}
//handler
static public void post(String request)
{
...
}
Depending on the version of C# that you're using, you may need to do:
categories.Add("campaigns", new categoryHandler(Campaigns.post));
As an aside, if you're using .NET 2.0 or above, you should be using the generic Dictionary<T,T> class instead of Hashtable.

Categories

Resources