How to pass multiple parameter in Task - c#

I have a function GetPivotedDataTable(data, "date", "id", "flag") is returning data in Pivoted format. I want to call this method using Task but how to pass multiple parameter in Task.

You could use lambda expression, or a Func to pass parameters:)
public Form1()
{
InitializeComponent();
Task task = new Task(() => this.GetPivotedDataTable("x",DateTime.UtcNow,1,"test"));
task.Start();
}
public void GetPivotedDataTable(string data, DateTime date, int id, string flag)
{
// Do stuff
}

In case that your parameters are of diferent types you could use an array of object and then typecast back to the original types.
Check out this console application example:
static void Main(string[] args)
{
var param1String = "Life universe and everything";
var param2Int = 42;
var task = new Task((stateObj) =>
{
var paramsArr = (object[])stateObj; // typecast back to array of object
var myParam1String = (string)paramsArr[0]; // typecast back to string
var myParam2Int = (int)paramsArr[1]; // typecast back to int
Console.WriteLine("");
Console.WriteLine(string.Format("{0}={1}", myParam1String, myParam2Int));
},
new object[] { param1String, param2Int } // package all params in an array of object
);
Console.WriteLine("Before Starting Task");
task.Start();
Console.WriteLine("After Starting Task");
Console.ReadKey();
}

You could create a helper class that will hold all parameters that you need in your task.

You can use "params" also. check c# params info
public class MyClass
{
public static void UseParams(params int[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
public static void UseParams2(params object[] list)
{
for (int i = 0; i < list.Length; i++)
{
Console.Write(list[i] + " ");
}
Console.WriteLine();
}
static void Main()
{
// You can send a comma-separated list of arguments of the
// specified type.
UseParams(1, 2, 3, 4);
UseParams2(1, 'a', "test");
// A params parameter accepts zero or more arguments.
// The following calling statement displays only a blank line.
UseParams2();
// An array argument can be passed, as long as the array
// type matches the parameter type of the method being called.
int[] myIntArray = { 5, 6, 7, 8, 9 };
UseParams(myIntArray);
object[] myObjArray = { 2, 'b', "test", "again" };
UseParams2(myObjArray);
// The following call causes a compiler error because the object
// array cannot be converted into an integer array.
//UseParams(myObjArray);
// The following call does not cause an error, but the entire
// integer array becomes the first element of the params array.
UseParams2(myIntArray);
}
}
/*
Output:
1 2 3 4
1 a test
5 6 7 8 9
2 b test again
System.Int32[]
*/

You can use Tuple
Task<Tuple<Tuple<Parame1,Parame2,Parame....>> Func()
{
}
var r = await Func();
r.Item1;
r.Item2;
r.Item.....

Related

Simoultanious data insertion into a list with multithreading

I'm trying to optimize a small program. So here is the basic idea:
I have an array of unfiltered data, and I wanna pass that to a function which will call another function, twice, for data filtering and insertion to a new list. The first call will take the data from original array in range from 0 => half of arrays length, and the second will do the same, but with range from half, to the last item. This way, I should make simultaneous insertion of filtered data into the same list. After the insertion is completed the filtered list can be passed to the rest of the program. Here's the code:
static void Main(string[]
{
// the unfiltered list
int[] oldArray = new int[6] {1,2,3,4,5,6};
// filtered list
List<int> newList= new List<int>();
// Functions is my static class
Functions.Insert(newList, oldArray )
Continue_Program_With_Filtered_List(newList);
// remaining functions...
}
And here is the Function class:
public static class Functions
{
public static void Insert(List<int> newList, int[] oldArray)
{
new Thread(() =>
{
Inserter(newList, oldArray, true);
}).Start();
new Thread(() =>
{
Inserter(newList, oldArray, false);
}).Start();
// I need to wait the result here of both threads
// and make sure that every item from oldArray has been filtered
// before I proceed to the next function in Main()
}
public static void Inserter(List<int> newList, int[] oldArray, bool countUp)
{
bool filterIsValid = false;
int length = oldArray.Length;
int halflen = (int)Math.Floor((decimal)length / 2);
if (countUp)
{
// from half length to 0
for (int i = 0; i < halflen; i++)
{
// filtering conditions here to set value of filterIsValid
if(filterIsValid)
newList.Add(oldArray[i]);
}
}
else
{
// from half length to full length
for (int i = halflen + 1; i < length; i++)
{
// filtering conditions here to set value of filterIsValid
if(filterIsValid)
newList.Add(oldArray[i]);
}
}
}
}
So the problem is that I must await Function.Insert() to complete every thread, and pass through every item before the newList is passed to the next function in Main().
I've no idea how to use Tasks or async method on something like this. This is just an outline of the program by the way. Any help?
In your case using PLINQ may also an option.
static void Main(string[] args)
{
// the unfiltered list
int[] oldArray = new int[6] { 1, 2, 3, 4, 5, 6 };
// filtered list
List<int> newList = oldArray.AsParallel().Where(filter).ToList();
// remaining functions...
}
You can also use AsOrdered() to preserve order
To come back to your initial question, here's what you can do
Note: Solution with minimal changes to your original code, whether there are other possible optimizations or not
Additional Note: Keep in mind that there can still be concurrency issues depending on what else you do with the arguments passing to that function.
public static async Task Insert(List<int> newList, int[] oldArray)
{
ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
var task1 = Task.Factory.StartNew(() =>
{
Inserter(concurrentBag, oldArray, true);
});
var task2 = Task.Factory.StartNew(() =>
{
Inserter(concurrentBag, oldArray, false);
});
await Task.WhenAll(task1, task2);
newList.AddRange(concurrentBag);
}
public static void Inserter(ConcurrentBag<int> newList, int[] oldArray, bool countUp)
{
//Same code
}
Edit: Your second for-loop is wrong, change it to this or you will loose one item
for (int i = halflen; i < length; i++)

How to pass enum as method parameter?

The task is to write a simple method that can sort int array (in ascending or descending order - should be set as enum type parameter of this method). I have written the method itself and enum, but I have no idea how to set enum as method parameter:(
Would be great to get any help from you, guys, cause I am completely new to coding.
class Program
{
public enum options
{
UpSortOption,
DownSortOption
}
public static void Main(string[] args)
{
int[] arr = new int[] { 3, 8, 0, 2, 16 };
}
static void orderArray(int [] array, options op)
{
switch(op)
{
case options.UpSortOption:
Array.Sort(array);
foreach (int number in array)
{
Console.Write(number + " ");
}
break;
case options.DownSortOption:
Array.Sort(array);
Array.Reverse(array);
foreach (int number in array)
{
Console.Write(number + " ");
}
break;
}
}
}
The signature of the method looks fine, Now you wanted to call this method by passing the first parameter of type integer array and the second parameter of type options for that you can use the following code:
orderArray(arr,options.UpSortOption);
Or else you can declare a variable of type options and pass that variable, the change you have to make for that case will be:
options optionsVariable = options.DownSortOption;
orderArray(arr,optionsVariable);
Let's take a step back to see if it helps your understanding.
If you have a method that takes a string and an int like this
string MyMethod(string str, int num)
{
// Do something
}
You'd use it like this
string rslt = MyMethod("Hello", 123);
What you've got here is something that takes in some stuff, does something to it, and gives you something in return. In this case MyMethod takes a string and an int, does something with them and returns a string which you then call rslt.
Your example follows the same basic pattern so you need to take your method - orderArray and give it the two things it wants - an int array and an option like this
int[] arr = new int[] { 3, 8, 0, 2, 16 };
orderArray(arr, options.UpSortOption);
Alternatively, you could create an options much like you'd create a string and then call your method like this
int[] arr = new int[] { 3, 8, 0, 2, 16 };
options myOption = options.UpSortOption;
orderArray(arr, myOption);
To fully illustrate the point that an enum as a parameter isn't any different from say a string you could modify your method like this
static void orderArray(int[] array, string op)
{
if (op == "UpSortOption")
{
Array.Sort(array);
foreach (int number in array)
{
Console.Write(number + " ");
}
}
else
{
Array.Sort(array);
Array.Reverse(array);
foreach (int number in array)
{
Console.Write(number + " ");
}
}
}
Then call it like this
int[] arr = new int[] { 3, 8, 0, 2, 16 };
string myOption = "UpSortOption";
orderArray(arr, myOption);
This is how you pass it as a parameter
orderArray(int [] array, typeof(options)){
//Beep bap boop
}
Hope this aids you.
Exactly that's how you set up Enum as a method parameter.
To call this method use:
orderArray(arr, options.UpSortOption);
You can also assign enum value to a variable and use this to call a method:
options sortOpt = options.UpSortOption;
orderArray(arr, sortOpt);
You can also cast integer to an enum:
orderArray(arr, (options)0);
OR
int opt = 0;
orderArray(arr, (options)opt);
Remembering, that if not specified otherwise, first element is 0, second is 1 and so on.
By the way, you should rather use PascalCase to name an enum type, like:
public enum Options
{ ... }

Permutation recursion C#

I have this function that call itself to find all the possible combination with the array of int. The problem is that the program calculate the first combination and then, when the recursion continues, the List of combination still contains that value and i don't understand why.
public static void Permutation(List<int> items, int h, List<int> actualCombination)
{
if (h == actualCombination.Count)
{
results[results.Count] = actualCombination;
}
else
{
for (int i = 0; i < items.Count; i++)
{
actualCombination.Add(items[i]);
List<int> temp = new List<int>(items);
temp.Remove(items[i]);
Permutation(temp, h, actualCombination);
}
return;
}
}
after that, i call the function in main. In my case the second parameter specify the combination length."Results" is a Dictionary composed by int as key and List as value that is used to save all the combination.
static void Main(string[] args)
{
Permutation(new List<int> { 1, 2, 3 }, 3, new List<int>());
Console.ReadKey();
}
I solved the problem by copying the List before of the function add.

C#: passing in array of a specific Enum type as params object[] argument

When attempting to pass in an array of a specific enum type as a function argument via params object[], I am unable to pass in an actual array without casting to object[] first. But if I do so I do not have access to the original enum type.
Given the enum and function shown below, this works fine:
var works = SomeFunction(Season.Fall, Season.Winter);
However, this fails because it cannot implicitly convert to object, so it passes array as first argument as opposed to individual arguments:
var seasons = new Season[] {Season.Fall, Season.Winter};
var fail = SomeFunction(seasons);
It also cannot cast to object[] because then later it is unable to determine the original type. How can I use a predetermined array to pass it in?
[Flags]
public enum Season : byte
{
None = 0,
Spring = 1,
Summer = 2,
Fall = 4,
Winter = 8
}
...
public Something SomeFunction(params object[] values)
{
...
foreach (var value in values)
{
var type = value.GetType();
...
}
}
UPDATE: it works to convert the Season[] array to object[], but that seems hokey:
var seasons = new object[original.Length];
for (int i = 0; i < original.Length; i++)
{
seasons[i] = original[i];
}
It's as simple as converting an object[] containing the enums as opposed to casting the array:
var original = new Season[] {Season.Fall, Season.Winter};
var selectedSeasons = new object[original.Length];
for (int i = 0; i < original.Length; i++)
{
selectedSeasons[i] = original[i];
}
var works = SomeFunctionWithObjectParamsArgs(selectedSeasons);
Yes, ultimately changing the function signature to be generic would be best, but doesn't apply in my case (third-party API).
Consider using the Cast<>() LINQ Method instead of a for loop, this looks cleaner:
var seasons = SomeFunction(seasons.Cast<object>().ToArray());
There's no other way you can cast an array of value types to an array of objects, you can't leverage array covariance in this case because it only works between arrays of compatible reference types.
This code compiles in .NET 3.5, 4.0, and 4.5. Are you getting a compiler error when you build?
class Program
{
static void Main(string[] args)
{
var p = new Program();
p.SampleFunc(Seasons.Winter, Seasons.Fall);
}
void SampleFunc(params object[] elements)
{
foreach(var element in elements)
{
if (element is Seasons)
{
// do something.
}
}
}
enum Seasons
{
Winter, Spring, Summer, Fall
}
}
I think this does it...
public enum MyEnum
{
EnumValue1,
EnumValue2,
EnumValue3
}
class Program
{
static void Main(string[] args)
{
var TheEnumList =(from list in Enum.GetValues(typeof (MyEnum)).Cast<int()
select new {EnumValueInstance = (MyEnum) list})
.ToList();
TheEnumList.ForEach(enumItem => Console.WriteLine(enumItem.EnumValueInstance));
var result = SomeFunction(TheEnumList);
Console.WriteLine(result);
Console.ReadKey();
}
public static MyEnum SomeFunction(params object[] values)
{
dynamic obj = values[0];
return obj[0].EnumValueInstance;
}
}

Create a generic datatype method

I have a C# application which has the two methods:
private void build_float_string() {
float[] mData = new float[1000];
Marshal.Copy(myPointer, mData, 0, 1000);
mData.ToList().ForEach(i => descriptor_string.Append(string.Format("{0}, ", i.ToString())));
}
Which results in the string 1.0, 1.1, 1.2, 1.3, .... And:
private void build_byte_string() {
byte[] mData = new byte[1000];
Marshal.Copy(myPointer, mData, 0, 1000);
mData.ToList().ForEach(i => descriptor_string.Append(string.Format("{0}, ", i.ToString())));
}
Which results in the string 1, 2, 3, 4, ....
Or whatever the data happens to be.
My question is: since these methods are identical - except for the float or byte data type, can I create a generic template method for this? I'm certain C++ can do this, but I don't know where to begin for doing this in C#.
If you dont want compiletime type safety there is also the dynamic Keyword (Assuming you are using c# 4.0 or above)
private void build_string<T>() where T : struct
{
try
{
T[] mData = new T[1000];
Marshal.Copy(myPointer,(dynamic) mData, 0, 1000);
descriptor_string.Append(String.Join(", ", mData.Select(item=>item.ToString()));
}
catch(RuntimeBinderException rbe)
{
// Handle case here where there is no suitable Marshal.Copy Method.
}
}
You can use Type class, or Type Parameters, I wish this helps:
class Program
{
static void Main(string[] args)
{
DateTime dtNow = DateTime.Now;
Console.WriteLine("String of float: " + getTheString<float>(12.7f));
Console.WriteLine("String of DateTime: " + getTheString<DateTime>(dtNow));
Console.WriteLine("The type name for a float number: " + getTheTypeName(18.25f));
Console.WriteLine("The type name for a DateTime object: " + getTheTypeName(dtNow));
Console.WriteLine("the result of making an instance for a float type: " +
makeOneInstanceOfType(20.2f, typeof(float)));
Console.WriteLine("the result of making an instance for a DateTime type: " +
makeOneInstanceOfType(0, typeof(DateTime)));
//Using GetType() instead of typeof(..)
Console.WriteLine("the result of making an instance for a DateTime type: " +
makeOneInstanceOfType(0, typeof(DateTime)));
Console.ReadLine();
}
//Using the Type Parameter (T) for creating instances of T which T is your type,
//specified when calling the method
private static string getTheString<T>(T arg)
{
return arg+"";
}
//Using Type by calling the GetType() method of the object
private static string getTheTypeName(object arg)
{
return arg.GetType().FullName;
}
//Direct use of Type, creates a float and fills is with the value if theType is float,
//otherwise makes an instance of theType.
private static object makeOneInstanceOfType(float valIfFloat, Type theType)
{
object instance;
if(theType.IsEquivalentTo(typeof(float)))
{
instance = valIfFloat;
}
else
{
instance = Activator.CreateInstance(theType);
}
return instance;
}
}
I don't think you can, because there's no generic overload for Marshal.Copy()
You could make the second part generic, however:
static StringBuilder BuildString<T>(IEnumerable<T> array, StringBuilder sb)
{
return array.Aggregate(sb, (s, f) => s.Append(string.Format("{0}, ", f.ToString())));
}
static StringBuilder BuildString<T>(IEnumerable<T> array)
{
return BuildString(array, new StringBuilder());
}
Using Aggregate is more efficient than ToList().ForEach() since the latter actually allocates an intermediate list.
private void build_the_string<T>() /* where T:struct */ {
T[] mData = new T[1000];
typeof(Marshal).GetMethod("Copy", BindingFlags.Static|BindingFlags.Public,
null, new Type[] { typeof(IntPtr), // or what myPointer really is,
typeof(T[]), typeof(Int32), typeof(Int32) }, null)
.Invoke(null, new object[] { myPointer, mData, 0, 1000 });
mData.ToList().ForEach(i => descriptor_string.Append(string.Format("{0}, ", i.ToString())));
}

Categories

Resources