Create a generic datatype method - c#

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())));
}

Related

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
{ ... }

C# Passing struct as parameter

I have the following code in C#:
public class ELL
{
public struct RVector
{
private int ndim;
private double[] vector;
public RVector(double[] vector) => (ndim, this.vector) = (vector.Length, vector);
public double this[int i] { get => vector[i]; set => vector[i] = value; }
public override string ToString()
{
string str = "(";
for (int i = 0; i < ndim - 1; i++)
str += vector[i].ToString() + ", ";
str += vector[ndim - 1].ToString() + ")";
return str;
}
}
private static void SwapVectorEntries(RVector b, int m, int n)
{
double temp = b[m];
b[m] = b[n];
b[n] = temp;
}
public static void M(string[] args)
{
var a = new double[4] { 1, 2, 3, 4 };
var b = new RVector(a);
Console.WriteLine(b);
SwapVectorEntries(b, 1, 2); // Why after this command, b will be changed?
Console.WriteLine(b);
}
}
In this program, i creates a struct RVector. After that, i use a method SwapVectorEntries which have a struct parameter. Because, Struct is a value type, so i think the method SwapVectorEntries will not change the struct parameter. But, in the program, after the command SwapVectorEntries(b, 1, 2);, b has changed. Please explain me about this. Thank you !
Problem is in this.You have an array wich is reference type.When you create your
double[] a = new double[4] { 1, 2, 3, 4 };
RVector b = new RVector(a);
you have two references to that array.After when you pass your object into the method,
SwapVectorEntries(b, 1, 2);
your object is copied,BUT your new object have the same reference to that array.Here your have only one array and many references to it.
B itself is not passed as a reference, but the copy of b has a Reference to the same double[].

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;
}
}

How to pass multiple parameter in Task

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.....

C# - Any thing similar to boost::any?

I have a requirement where:
1. I need to store objects of any type in list
2. Avoid casting calls as much as possible
To that end I tried to come up with something. No matter what I tried I could not get rid of boxing\unboxing. I wanted to know whether any of you have come across something that will achieve it.
The class I have created is mostly useless unless you are dealing with small collections because in terms of memory and performance it takes 1.5 times ArrayList. I am trying to find ways to improve at least one of them as well (preferably performance).
Any feedback is appreciated.
public class Castable
{
Object _o;
public override bool Equals(object obj) { return base.Equals(obj); }
public override int GetHashCode() { return base.GetHashCode(); }
public bool Equals<T>(T obj)
{
T v1 = (T)this._o;
//T v2 = obj;
//var v2 = obj; // Convert.ChangeType(obj, obj.GetType());
// This doesn't work.. (Cannot convert T to Castable
//var v2 = Convert.ChangeType(this.GetType() == obj.GetType() ?
//((Castable)obj)._o.GetType(), obj.GetType());
//if (((T)this._o) != obj) //<== why this doesn't work?
//if (v1 == obj) //<== "Operator '==' cannot be applied to operands of type 'T' and 'T'"
if(v1.Equals(obj))
{
return true;
}
return false;
}
public bool Equals(Castable obj)
{
var v = Convert.ChangeType(obj._o, obj._o.GetType());
return Equals(v);
}
public static bool operator ==(Castable a, Castable b)
{
return a.Equals(b);
}
public static bool operator !=(Castable a, Castable b)
{
return !a.Equals(b);
}
#region HOW CAN WE USE GENRIC TYPE FOR == and != OPERATOR?
public static bool operator ==(Castable a, object b)
{
return a.Equals(b);
}
public static bool operator !=(Castable a, object b)
{
return !a.Equals(b);
}
#endregion
public void Set<T>(T t) { _o = t; }
public T Get<T>() { return (T)_o; }
public static long TestLookup(IList list, int elements, int lookups)
{
object value;
Stopwatch watch = new Stopwatch();
watch.Start();
for (long index = 0; index < lookups; ++index)
{
value = list[random.Next(0, elements - 1)];
}
watch.Stop();
return watch.ElapsedMilliseconds;
}
public static long TestCompare(IList list, int elements, int lookups)
{
//object value;
bool match;
Stopwatch watch = new Stopwatch();
watch.Start();
for (long index = 0; index < lookups; ++index)
{
match = random.Next() == (int)list[random.Next(0, elements - 1)];
}
watch.Stop();
return watch.ElapsedMilliseconds;
}
public static long TestCompareCastable(IList<Castable> list, int elements, int lookups)
{
//object value;
bool match;
Stopwatch watch = new Stopwatch();
watch.Start();
for (long index = 0; index < lookups; ++index)
{
match = list[random.Next(0, elements - 1)] == random.Next(); //most of the times 1.4 times
//match = list[random.Next(0, elements - 1)].Equals(random.Next()); // may be 1.3 times ArrayList
}
watch.Stop();
return watch.ElapsedMilliseconds;
}
public static void Test(int elements, int lookups, int times)
{
List<int> intList = new List<int>();
List<Castable> castableList = new List<Castable>();
ArrayList intArrayList = new ArrayList();
if (Stopwatch.IsHighResolution)
Console.WriteLine("We have a high resolution timer available");
long frequency = Stopwatch.Frequency;
Console.WriteLine(" Timer frequency in ticks per second = {0}", frequency);
for (int index = 0; index < elements; ++index)
{
intList.Add(random.Next());
intArrayList.Add(random.Next());
Castable c = new Castable();
c.Set(random.Next());
castableList.Add(c);
}
long ms = 0;
string result = "";
string ratios = "";
for (int time = 0; time < times; ++time)
{
ms = TestLookup(intList, elements, lookups);
result += "intList Lookup Time " + ms.ToString() + " MS\n";
ms = TestLookup(castableList, elements, lookups);
result += "intArrayList Lookup Time " + ms.ToString() + " MS\n";
ms = TestLookup(intArrayList, elements, lookups);
result += "castableList Lookup Time " + ms.ToString() + " MS\n";
ms = TestCompare(intList, elements, lookups);
result += "intList Compare Time " + ms.ToString() + " MS\n";
long msarraylist = ms = TestCompare(intArrayList, elements, lookups);
result += "intArrayList Compare Time " + ms.ToString() + " MS\n";
ms = TestCompareCastable(castableList, elements, lookups);
result += "castableList Compare Time " + ms.ToString() + " MS\n";
ratios += String.Format("round: {0}, ratio: {1}\n", time, (float)ms / msarraylist);
}
//MessageBox.Show(result);
MessageBox.Show(ratios);
int i = 10;
Castable o1 = new Castable();
o1.Set(i);
int j = 10;
Castable o2 = new Castable();
o2.Set(j);
if (!o1.Equals(10))
{
Console.WriteLine("unequal");
}
if (!o1.Equals(o2))
{
Console.WriteLine("unequal");
}
if (o1 != j)
{
Console.WriteLine("unequal");
}
int x = o1.Get<int>();
}
}
EDIT
In short I am trying to achieve:
#winSharp93: yes, in short:
List GenericGenericCollection = new List ();
GenericGenericCollection.Add(new string("a sonnet");
GenericGenericCollection.Add(42);
GenericGenericCollection.Add(new MyOwnCustomType);
EDIT AGAIN
There are two ways I found:
1. In .NET 4, a new 'dynamic' keyword is introduced. If you replace the line Object _o; with dynamic _o; you can use the code as it is. The problem is although dynamic supposed to be dynamic type, performance is just like boxing..
The performance can be improved by adding implicit (I prefer) or explicit casting operator instead of relying on generic == operator.
Based on http://igoro.com/archive/fun-with-c-generics-down-casting-to-a-generic-type/ I added following class. This takes care of boxing and performance - with following class performance is little better than ArrayList of int or Castable. Of course it has long way to go when List<int> compared.
The only problem, from my point of view is, once object is assigned to plain Any object to get concrete type embedded inside AnyInternal<T>. Neither I could find a way to have method T Get(). Even keyword dynamic fails at runtime at statment:
Any.AnyInternal<dynamic> any = (Any.AnyInternal<dynamic>)anyInstanceContainingAnyInternalForInt;
//too bad I can't seal Any after AnyInternal<T> has derived from it.
public abstract class Any
{
public static implicit operator int(Any any)
{
return Any.ToType<int>(any).Data;
}
public static AnyInternal<T> ToType<T>(Any any)
{
return ((AnyInternal<T>)any);
}
public class AnyInternal<T> : Any
{
private T _data;
public T Data { get { return _data; } }
public AnyInternal(T data)
{
_data = data;
}
}
}
Use the generic List<T> (inside System.Collections.Generic) instead of ArrayList.
There won't happen any boxing / unboxing for value types.

Categories

Resources