C#: Generic list of enum values - c#

Is there a way to create a method that gets an enum type as a parameter, and returns a generic list of the enum underlying type from it's values, no matter if the underlying type is int\short byte etc'...
I saw this answer of Jon Skeet, but it looks way too complicated.

If you want to pass in a Type, it can't really be usefully generic - you'd have to return a single type that isn't directly related to the input, hence something like:
public static Array GetUnderlyingEnumValues(Type type)
{
Array values = Enum.GetValues(type);
Type underlyingType = Enum.GetUnderlyingType(type);
Array arr = Array.CreateInstance(underlyingType, values.Length);
for (int i = 0; i < values.Length; i++)
{
arr.SetValue(values.GetValue(i), i);
}
return arr;
}
This is a strongly-typed vector underneath, so you could cast that to int[] etc.

While Marc's answer isn't wrong its somewhat unnecessary.
Enum.GetValues(type) returns a TEnum[] so this method is kind of unnecessary as if you know the underlying type you can just cast TEnum[] to its underlying type array.
var underlyingArray = (int[])Enum.GetValues(typeof(StringComparison));
is valid C# that will compile and won't throw an exception at runtime. Since you wanted a list once you have the array you can pass it to the List<Tunderlying> constructor or you can just call the ToArray() extension method.
Edit: you could write the function as such::
public static TUnderlying[] GetValuesAs<TUnderlying>(type enumType)
{
return Enum.GetValues(enumType) as TUnderlying[];
}
But then you would have to know the underlying type first.

Related

C#: Why does dynamic help determine type argument for use in generic methods?

I'm working with reflection to create some meta-tests to ensure equality between two instances of the same type.
As such, I'm using a lot of vars and generics.
One thing I've noticed is that with my generic functions, sometimes the Type argument is object (presumably when it can't determine the type) and other times it's the correct type.
Example:
Generic methods
public static RT[] CreateArrayWithNumItems<RT>(RT baseArgument, int numItems)
{
var a = new List<RT>();
for (int i = 0; i < numItems; i++)
a.Add((RT)DataObjectCreator.CreateUninitializedObject(typeof(RT)));
return a.Select(x => (RT)x).ToArray();
} //actual implementation more complex
private static T UnboxObject<T>(T boxedObject)
=> boxedObject;
public static object CreateUninitializedObject(Type typeObject)
=> typeObject == typeof(string) ? "" : FormatterServices.GetUninitializedObject(typeObject);
Use of methods:
var a = Model.GetType();
var unitializedObject = CreateUninitializedObject(a); //returns typed object
var objectArray = CreateArrayWithNumItems(unitializedObject, 1); //returns object array
var uob = UnboxObject(unitializedObject); //returns typed object
var uobObjectArray = CreateArrayWithNumItems(uob, 1); //returns object array
var typedArray = CreateArrayWithNumItems((dynamic) unitializedObject, 1); //returns typed object array
This seems strange to me (a.k.a I'm missing some knowledge), so I have a few questions about it.
Given the same variable, why does UnboxObject return a typed object and CreateArrayWithNumItems return an array of object?
Given the typed object uob why does CreateArrayWithNumItems return an array of object?
Lastly (and most importantly), why does casting to dynamic prior to calling CreateArrayWithNumItems allow the generic method to determine the type?
Without dynamic, the compiler performs all the type evaluations based on static analysis; assuming that CreateUninitializedObject returns object (presumably via FormatterServices), the call to CreateArrayWithNumItems infers the generic type parameters based on that static type, i.e.
var objectArray = CreateArrayWithNumItems(unitializedObject, 1);
becomes
var objectArray = CreateArrayWithNumItems<object>(unitializedObject, 1);
precisely because unitializedObject is object.
With dynamic, the runtime performs the work, but now it has knowledge of the actual object at runtime, so it knows that the type is (whatever Model is). The runtime then constructs something like:
dynamic objectArray = CreateArrayWithNumItems<TheActualType>((TheActualType)unitializedObject, 1);
(how it actually does it is much more complex; it could look for non-generic methods too, for example)
So yes, using dynamic can be a sneaky way to go from reflection (object/Type) code to strongly-typed generic code, but: it has a cost: dynamic involves more work at runtime - additional reflection, and additional runtime IL emit. You also need to be aware that typedArray is now also dynamic (unless you cast it to something else), so everything you do with typedArray becomes dynamic. Increasing costs.

Know if a type can be converted to string representing the data [duplicate]

I am writing an interop between a php service and our crm. One of the things I need to do is make sure that simple types get converted ToString() for use later in a json converter.
I am not sure even what the name is for 'simple types' but it can be defined like this... "an object that represents a low level variable type, containing a single value, not a class or anything with executable functions etc"
I've found that int, string, bool, double, and surprisingly enum will ToString() with pretty predictable results.
int x = 0;
bool y = true;
double z = 1.59 // money
CustomEnum theEnum = CustomEnum.somevalue;
x.ToString() results in "0"
y.ToString() results in "true"
z.ToString() results in "1.59"
theEnum.ToString() results in "somevalue"
But if I use this:
List<int> iList = new List<int>();
iList.Add(1);
MyClass theClass = new MyClass();
iList.ToString() results in "System.Collections.Generic.List`1[System.Int32]"
theClass.ToString() results in "STTI.NKI.Interop.MyClass"
I'm not limited to lists. I could have an ExpandoObject, or a class etc.
I understand EXACTLY why this happens, and I want to know if there is a quick way to determine if an object of unknown type will ToString() into an expected value, and not the type name. I find it an antipattern to do something like
switch (theObject.GetType())
case typeof(int):
case typeof(bool):
case typeof(doulble):
etc
I am not sure what the terms are, so googling my answer is proving difficult.
So you want to check whether a type has a overridden ToString method? Why not just check whether the value returned by ToString is equal to the value returned by the default implementation of ToString?
From here, we know the default implementation of ToString is
return GetType().ToString();
So, we can use this to check whether an object has overridden the ToString method:
bool toStringOverridden = someObject.GetType().ToString() !=
someObject.ToString();
The ToString method is a virtual one and the default implementation is defined in the Object class and simply returns the name of the type of the object:
public virtual string ToString()
{
return this.GetType().ToString();
}
int for example, overrides this method to return a meaningful representation.
What you can do is use reflection to detect whether a type overrides the ToString method like this:
public static bool OverridesToString(Type type)
{
return type.GetMethod("ToString", new Type[0]).DeclaringType != typeof(object);
}
If it does, there is a very good chance that the ToString method would return something meaningful.
Option 1: make sure that every Object will overwrite ToString().
Option 2: Use reflection to get all object properties and concat them.
Maybe you can do something similar to this:
bool ToStringIsTyped<T>(T myObj)
{
return myObj.ToString().Contains(typeof(T).FullName);
}
It may not work in all cases, but possibly could be expanded
I Think this is what you are looking, in the GetMethod the second argument is an empty array to watch for the .ToString(), just convert the i.GetType().GetMethod("ToString", new Type[] { }).DeclaringType == typeof(object) to a function and there you go.
class Program
{
static void Main(string[] args)
{
int i = 55;
var s = "some string";
var x = new List<string>();
Console.WriteLine(i.ToString());
Console.WriteLine(i.GetType().GetMethod("ToString", new Type[] { }).DeclaringType == typeof(object));
Console.WriteLine(s.ToString());
Console.WriteLine(s.GetType().GetMethod("ToString",new Type[]{}).DeclaringType == typeof(object));
Console.WriteLine(x.ToString());
Console.WriteLine(x.GetType().GetMethod("ToString",new Type[]{}).DeclaringType == typeof(object));
}
}
...way to determine if an object of unknown type will ToString() into an expected value, and not the type name...
The default implementation of ToString() on object, according to documentation, returns "the fully qualified name of the object's type".
So we could come up with the hypothesis that whenever ToString() is overridden, its output will be "useful" in the sense you specified in the question.
To detect whether a function called is an override, we can make use of this answer, like so:
if(typeof(ObjectX).GetMethod("ToString").DeclaringType == typeof(ObjectX))
{
/* ObjectX has overridden ToString() */
}
else
{
/* ObjectX has inherited ToString() from its base class(es) */
}
Using reflection can add too much overhead, so I reckon it's better to create a generic method and add a constraint like: where T : IFormattable

What does T stands for in C#? [duplicate]

This question already has answers here:
What does "T" mean in C#?
(7 answers)
Closed 9 years ago.
public void DisplayValue<T>(T field, string fieldname)
What does T stands for in above code?
Whats the benefit to do so?
Where we can use this?
From Generics (C# Programming Guide)
... by using a generic type parameter T you can write a single class
that other client code can use without incurring the cost or risk of
runtime casts or boxing operations
It is a Generic Type Parameter.
A generic type parameter allows you to specify an arbitrary type T to a method at compile-time, without specifying a concrete type in the method or class declaration.
For example:
public T[] Reverse<T>(T[] array)
{
var result = new T[array.Length];
j=0;
for(int i=array.Length; i>= 0; i--)
{
result[j] = array[i];
j++;
}
return result;
}
reverses the elements in an array. The key point here is that the array elements can be of any type, and the function will still work. You specify the type in the method call; type safety is still guaranteed.
So, to reverse an array of strings:
string[] array = new string[] { "1", "2", "3", "4", "5" };
var result = reverse(array);Will produce a string array in result of { "5", "4", "3", "2", "1" }
This has the same effect as if you had called an ordinary (non-generic) method that looks like this:
public string[] Reverse(string[] array)
{
var result = new string[array.Length];
j=0;
for(int i=array.Length; i >= 0; i--)
{
result[j] = array[i];
j++;
}
return result;
}The compiler sees that array contains strings, so it returns an array of strings. Type string is substituted for the T type parameter.
Generic type parameters can also be used to create generic classes.
In the example you gave of a SampleCollection, the T is a placeholder for an arbitrary type; it means that SampleCollection can represent a collection of objects, the type of which you specify when you create the collection.
So:
var collection = new SampleCollection<string>();
creates a collection that can hold strings. The Reverse method illustrated above, in a somewhat different form, can be used to reverse the collection's members.
Type Parameters T: The type of elements in the list.
according to MSDN documentation.
Whats the benefit to do so?
The method can take anonymous lists of a type.
Where we can use this?
For example when the same manipulation has to be done on several lists of several types.

Is there a generic unbox function like in f#?

I m trying to use object handlers and I have this working fine to put stuff in memory. But when I look up the object again I return:
object(object[,])
or
object(double[,])
how do I unbox this in c#?
object(double[,]) boxedobj = ....
double[,] unboxedobj = unbox(boxedobj);
Ideally I would like to do this in a generic way so that it doesnt matter whether the tybe is double[] or double[,] or object[,], etc
The F# unbox function is pretty much just doing cast to any other type that you specify. In C#, this could be written like this:
static R Unbox<R>(object anything) {
return (R)anything;
}
So in your case with double[,] you'd need something like:
var array = (double[,])boxed;
In most cases unbox<'R> anything would just translate to casting using (R)anything. The only case where this does not work is when you are in another generic method and you are casting between two generic types. In that case, you need to go to object first (to make sure that the value is boxed):
static R Unbox<R, T>(T anything) {
return (R)(object)anything;
}
Unless I'm missing your point, casting to/from object should automatically box/unbox value types for you (an array is not a value type, BTW):
double d = 0.0; // not boxed
object obj = d; // boxed
double d2 = (double)obj; // unboxed
The bigger question is - why do you care if its boxed or not?

params object[] method parameters boxed?

Ok, so when I have a method that looks like
getPacket(params object[] inputs)
{
}
Is the inputs array an array of boxed variables or is it simply just an array of the original types (im sending multiple different types tho, eg. short, int, bool)
If they are boxed can you do run-time unboxing to the original type without knowing the original type?
If they aren't boxed, how can I tell whether it's an int, short, bool etc. as I want to be able to make a single method that puts together a byte array from a whole stack of different types.
Another question, are the objects in the array in the same order as they were passed in the method invocation?
The objects in the array will be in the same order that they were passed to the method and they will be boxed if the source parameter is a value type.
You can use the is keyword to check the underlying type of each object and act accordingly, for example:
static void Main(string[] args)
{
Receive(1, true);
}
static void Receive(params object[] values)
{
foreach (var v in values)
{
if (v is int)
{
// ...
}
else if (v is bool)
{
// ...
}
}
}
if you have an array of objects, then yes, if for example you put integers in the array, they will be boxed. I dont know of any unboxing methods without knowing the actual types involved, so you will have to cast the items in the array to whatever value they actually represent.

Categories

Resources