Get an enumerated field from a string - c#

Bit of a strange one this. Please forgive the semi-pseudo code below. I have a list of enumerated values. Let's say for instance, like so:
public enum Types
{
foo = 1,
bar = 2,
baz = 3
}
Which would become, respectfully, in the code:
Types.foo
Types.bar
Types.baz
Now I have a drop down list that contains the following List Items:
var li1 = new ListItem() { Key = "foo" Value = "Actual Representation of Foo" }
var li2 = new ListItem() { Key = "bar" Value = "Actual Representation of Bar" }
var li3 = new ListItem() { Key = "baz" Value = "Actual Representation of Baz" }
for the sake of completeness:
dropDownListId.Items.Add(li1); dropDownListId.Items.Add(li2); dropDownListId.Items.Add(li3);
Hope that everyone is still with me. What I want to do is to on the Autopostback is take the string "foo" and convert that to Types.foo - without using a switch (as the enumerated values are generated from a database and may change).
I hope that makes sense? Any idea where to even start?

Sure:
Types t;
if(Enum.TryParse(yourString, out t)) // yourString is "foo", for example
{
// use t
}
else
{
// yourString does not contain a valid Types value
}
There's also an overload that takes a boolean that allows you to specify case insensitiveness:
http://msdn.microsoft.com/en-us/library/dd991317.aspx
Enum.TryParse is new in .NET 4. If you're stuck on a previous version, you'll have to use the non-typesafe Enum.Parse method (which throws an exception in case of conversion failure, instead of returning false), like so:
try
{
Types t = (Types)Enum.Parse(typeof(Types), yourString);
// use t
}
catch(ArgumentException)
{
// yourString does not contain a valid Types value
}
Enum.Parse also has an overload for case insensitiveness.

So, you want: Enum.Parse(typeof(Types), postbackValue)
or did I miss something?

If I understood correctly, you can do:
Types fooEnum = Enum.Parse(typeof(Types), "foo");
See: http://msdn.microsoft.com/en-us/library/essfb559.aspx

Related

Cleaner way to include nulls/default values in arrays of anonymous types?

So this code compiles:
var foo = new[]
{
new { prop1 = 1, prop2 = "whatever" },
default,
new { prop1 = 2, prop2 = "something" },
};
But the following doesn't:
var foo = new[]
{
new { value = new { prop1 = 1, prop2 = "whatever" } },
new { value = default },
new { value = new { prop1 = 2, prop2 = "something" } },
};
And so far the only way I can find to get it to do so is via:
T MakeDefaultOf<T>(T dummy) => default(T);
var foo = new[]
{
new { value = new { prop1 = 1, prop2 = "whatever" } },
new { value = MakeDefaultOf(new { prop1 = 0, prop2 = "" }) },
new { value = new { prop1 = 2, prop2 = "something" } }
};
But it would seem for both the first two examples the compiler has enough information to work out the implicit type of 'default' - so is there a reason it doesn't? Are there any ways of achieving what I want without an ancillary function or variable?
Depending on your use case, you may get away with this:
var foo = new[]
{
new { prop1 = 1, prop2 = "whatever" },
default,
new { prop1 = 2, prop2 = "something" },
}.Select(x => new { value = x } ).ToArray();
I'm not aware of any syntax sugar to initialize such default values.
The reason why second (new {value = default} ) initialization fails is due to
C# arrays
For a single-dimensional array, the array initializer must consist of a sequence of expressions that are assignment compatible with the element type of the array.
Compiler checks type of each individual element and then computes the best suitable base type. There is no second pass over objects to figure out if all can be made compatible with the likely resulting type (which had to be the first step to implement the behavior you expect).
As result the compiler tries to reason what new {value = default} is and there is not enough information to construct the type. Note that passing null instead default would not help as it will not define particular type - the helper method you have need to be used to provide the exact type for null at this point. And the resulting type must be exactly the same as all other elements of array because anonymous types must match exactly to be assignment compatible - C# anonymous types:
Anonymous types are class types that derive directly from object, and that cannot be cast to any type except object...
...If two or more anonymous object initializers in an assembly specify a sequence of properties that are in the same order and that have the same names and types, the compiler treats the objects as instances of the same type.
But it would seem for both the first two examples the compiler has
enough information to work out the implicit type of 'default' - so is
there a reason it doesn't?
The problem is not related to the array per se. It's the fact that the compiler simply doesn't allow you to initialize an anonymous type with a null/default value according to Compiler Error CS0828:
An anonymous type cannot be initialized with a null value or an unsafe
type, or a method group or anonymous function.
Let's forget about the array for a moment and consider the following code:
var bar = new { value = default }; // Or new { value = null }
Now, the compiler has no way of knowing the type of value and, therefore, can't infer the type of bar.
That is the cause of the problem at hand. All you did is that you added bar to an array of anonymous types. Yes, the compiler should be able to infer the type of the array element based on the other elements but now bar, as an element of the array, has a type that the compiler doesn't recognize, it wasn't able to make sure all the elements of the array are of the same type (because it's an implicitly typed array).

cast list of anonymous type to list of object

I am trying to create a anonymous list which can hold any data type with intellisense support but without creating a class.
So I found below solution to use anonymous type.
var list = new[]
{
new { Number = 10, Name = "Smith" },
new { Number = 10, Name = "John" }
}.ToList();
foreach (var item in list)
{
Console.WriteLine(item.Name);
}
But what if I want a method which returns above anonymous type.
public List<object> GetData()
{
var list = new[]
{
new { Number = 10, Name = "Smith" },
new { Number = 10, Name = "John" }
}.ToList();
return list;
}
Compile Time Error:
Cannot implicitly convert type
'System.Collections.Generic.List<>' to 'System.Collections.Generic.List
Is it possible to cast list of anonymous type to list of object with intellisense support ?
Update:
The reason we don't want to create a type , because we just want to do some data manipulation using the anonymous type and populate some other objects that's all.
Here are the ways possible:
Return a List<object>, which means you have no intellisense on the receiving end
Return a List<dynamic>, which means you have no intellisense on the receiving end, but perhaps easier to access members you know are there than through reflection
Return a List<T> but then you will have to provide an example of how T is supposed to look and this won't be any more safe at runtime than dynamic is
Return a tuple of the new type that came with C# 7
Point 1 and 2 can be easily solved by just ensuring the list is of that type:
...
}.ToList<object>();
Point 3 is a hack but I'll post it below.
Point 4 can be solved with this syntax:
public List<(int Number, string Name)> GetData()
{
var list = new[]
{
(Number: 10, Name: "Smith"),
(Number: 10, Name: "John")
}.ToList();
return list;
}
This will give you intellisense for a while but the naming of the properties is a hack by the compiler and if you start passing these values around they will easily fall back to .Item1 and .Item2.
To cast an object to a specific type you can use a hack which only works in the same assembly that the anonymous object was created in, and that is that multiple anonymous types used around in your code, which has the same properties, in the same order, with the same property types, all end up being the same anonymous type.
You can thus cast an object to a specific anonymous type with this hackish code:
public T AnonymousCast<T>(object value, T example) => (T)value;
public IEnumerable<T> AnonymousCastAll<T>(IEnumerable<object> collection, T example) => collection.OfType<T>();
You would use it in your case like this:
var d = AnonymousCast(GetData()[0], new { Number = 0, Name = "" });
This is no more safe than using dynamic as there is no guarantee the object returned from GetData actually is of that anonymous type.
In short, use a named type.

Call function in dynamic linq

I'm trying to call a function in a dynamic linq select statement, but im getting error:
No property or field 'A' exists in type 'Tuple2'
Example code:
void Main()
{
var a = new Tuple<int, int>(1,1);
var b = new[]{ a };
var q = b.AsQueryable().Select("A.Test(it.Item1)");
q.Dump();
}
public static class A
{
public static int Test(int i)
{
return i++;
}
}
How should I change my code to get this working?
If I call built in function Convert.ToInt32 for example it works fine.
var q = b.AsQueryable().Select("Convert.ToInt32(it.Item1)");
Also how do I cast a property using dynamic linq?
var q = b.AsQueryable().Select("((float)it.Item1)");
I'll say that the dynamic-linq isn't "strong enough" to do these things. It looks for methods only in the given objects and some special classes: Math, Convert, the various base types (int, float, string, ...), Guid, Timespan, DateTime
The list of these types is clearly visible if you use ilspy/reflector on the file. They are in System.Linq.Dynamic.ExpressionParser.predefinedTypes .
Now, clearly I could be wrong, but this works: .Select("Guid.NewGuid().ToString()").Cast<string>().ToArray()
showing that it's quite probable that that is the "correct" list.
There is an article here on how to modify Dynamic LINQ if you are interested http://www.krizzcode.com/2012/01/extending-dynamiclinq-language.html
Now, an intelligent man would take the source of dynamic linq and simply expand that array... But here there aren't intelligent men... There are only programmers that want blood! Blood but especially innards!
var type = typeof(DynamicQueryable).Assembly.GetType("System.Linq.Dynamic.ExpressionParser");
FieldInfo field = type.GetField("predefinedTypes", BindingFlags.Static | BindingFlags.NonPublic);
Type[] predefinedTypes = (Type[])field.GetValue(null);
Array.Resize(ref predefinedTypes, predefinedTypes.Length + 1);
predefinedTypes[predefinedTypes.Length - 1] = typeof(A); // Your type
field.SetValue(null, predefinedTypes);
Do this (with the types you want) BEFORE the first call to Dynamic Linq (because after the first call the methods/properties of these types are cached)
Explanation: we use reflection to add our object(s) to this "special list".
I know there is already an accepted answer on this but it did not work for me. I am using Dynamic Linq 1.1.4. I wanted to do a query like this
$.GetNewestRisk() == null
Where GetNewestRisk() is a public method on the object represented by $. I kept getting this error "Error running query, Methods on type 'Patient' are not accessible (at index 2)".
I found in the source code there is a GlobalConfig object that allows a custom provider to be assigned which will hold all of the types you may want to work with. Here is the source code for the custom provider:
public class CustomTypeProvider: IDynamicLinkCustomTypeProvider
{
public HashSet<Type> GetCustomTypes()
{
HashSet<Type> types = new HashSet<Type>();
types.Add(typeof(Patient));
types.Add(typeof(RiskFactorResult));
types.Add(typeof(PatientLabResult));
types.Add(typeof(PatientVital));
return types;
}
}
Here is how I am using it:
System.Linq.Dynamic.GlobalConfig.CustomTypeProvider = new CustomType();
After making this call I am able to call methods on the objects inside of the expression.
#xanatos answer doesn't work for .Net Core version. So I've found something similar related by #Kent on the System.Dynamic.Linq.Core tests DynamicExpressionParserTests written by the library's author himself.
The given TestCustomTypeProviderClass allows you to use the DynamicLinqType class annotation which is pretty usefull for this problem.
To answer to question, you then just needed to defined the class (ensure to annotate with DynamicLinqType) :
[DynamicLinqType]
public static class A
{
public static int Test(int i)
{
return i++;
}
}
Add a customTypeProvider as mentioned above :
private class TestCustomTypeProvider : AbstractDynamicLinqCustomTypeProvider, IDynamicLinkCustomTypeProvider
{
private HashSet<Type> _customTypes;
public virtual HashSet<Type> GetCustomTypes()
{
if (_customTypes != null)
{
return _customTypes;
}
_customTypes = new HashSet<Type>(FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly }));
return _customTypes;
}
}
and use a ParsingConfig with the configurable Select to call it :
var config = new ParsingConfig
{
CustomTypeProvider = new TestCustomTypeProvider()
};
var q = b.AsQueryable().Select(config, "A.Test(it.Item1)");
#Armand has put together a brilliant solution for this issue, and being the only solution I was able to find regarding this I want to add to it for anyone who tries the same approach.
The class that is marked with...
[DynamicLinqType]
... must be taken into consideration when you run the following line:
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { GetType().GetTypeInfo().Assembly })
In the solution provided above, this assumes the class that contains the function to be evaluated is on the same class the code currently resides in. If the methods are to be used outside of said class, the assembly will need to change.
FindTypesMarkedWithDynamicLinqTypeAttribute(new[] { typeof(AnotherClassName).Assembly })
Nothing changes from the solution above, this is just for clarification for anyone attempting to use it.
As regards the current version (1.2.19) of Dynamic LINQ, you will probably get another exception:
System.Linq.Dynamic.Core.Exceptions.ParseException : Enum value 'Test' is not defined in enum type 'A'
To make DLINQ know your type 'A', you have two options:
Set up parsing config with your own custom types provider where you directly specify the type 'A'.
Mark your type with the attribute [DynamicLinqType]. If that type is loaded into the current domain (that's the usual case), you don't have to do anything more since the default custom type provider already scans the current AppDomain for types marked with [DynamicLinqType]. And only if that's not the case, i.e. your type is not loaded into the current domain, you have to do something like in that answer.
What if you would like to use both approaches - the first for type 'A' and the second for type 'B'? In that case, you just have to "merge" your type 'A' with the default provider types:
public class DynamicLinqTests
{
[Test]
public void Test()
{
var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var parsingConfig = new ParsingConfig
{
ResolveTypesBySimpleName = true,
CustomTypeProvider = new TestCustomTypesProvider()
};
var queryWithA = b.AsQueryable().Select(parsingConfig, "A.Test(it.Item1)");
queryWithA.ToDynamicList();
var queryWithB = b.AsQueryable().Select(parsingConfig, "B.Test(it.Item1)");
queryWithB.ToDynamicList();
}
public static class A
{
public static int Test(int i)
{
return i++;
}
}
[DynamicLinqType]
public static class B
{
public static int Test(int i)
{
return i++;
}
}
public class TestCustomTypesProvider : DefaultDynamicLinqCustomTypeProvider
{
public override HashSet<Type> GetCustomTypes()
{
var customTypes = base.GetCustomTypes();
customTypes.Add(typeof(A));
return customTypes;
}
}
}
I may be confused but your syntax whereby you are using a string in your Selects doesn't compile for me. The following syntax works:
var q = b.AsQueryable().Select(it => A.Test(it.Item1));
var b = new[]{ a };
The above array is don't know what type of array , and it's not type safe ?
Your values are assigned in variant data type so it's not integer value (I think string value) ,when you get this values in your query must need to convert.toint32() because your class parameter data type is integer
Please try it
var b = new **int**[]{ a };
instead of var b = new[]{ a };
The important hint is here (in bold):
No property or field 'xxx' exists in **type** 'xxx'
And Please look this for previous discussion :
Dynamic Linq - no property or field exists in type 'datarow'
The following works for me:
var a = new Tuple<int, int>(1, 1);
var b = new[] { a };
var q = b.AsQueryable().Select(it=>A.Test(it.Item1));
var q1 = b.AsQueryable().Select(it => Convert.ToInt32(it.Item1));
var q2 = b.AsQueryable().Select(it => (float) it.Item1);

Please decipher this C# expression for me

What does this mean??
var cdParams = (includeUniversals)
? new[] {pageDictionary[pageName], pageDictionary[CNNService.UniversalPage.Name]}
: new[] {pageDictionary[pageName]};
Basically it boils down to what does ? mean and what does new[] mean?
It's roughly equivalent to this:
Foo[] cdParams; // Use the correct type instead of Foo. NB: var won't work here.
if (includeUniversals) {
dParams = new Foo[2];
dParams[0] = pageDictionary[pageName];
dParams[1] = pageDictionary[CNNService.UniversalPage.Name];
} else {
dParams = new Foo[1];
dParams[0] = pageDictionary[pageName];
}
It's a ternary expression. If the condition is true, then execute the first case. If it is false, then execute the second case.
If the boolean includeUniversals evaluates to true then return a new anonymous object array containing pageDictionary[pageName] and pageDictionary[CNNService.UniversalPage.Name] otherwise return a new anonymous object array containing pageDictionary[pageName]
That what you are looking for?
var cdParams // type inferred by the compiler
= (includeUniversals) ? // if includeUniversals is true
// then cdParams = new a new array with 2 values coming from a dictionary
new[] { pageDictionary[pageName], pageDictionary[CNNService.UniversalPage.Name] }
// otherwise, cdParams = a new array with one value
: new[] { pageDictionary[pageName] };
See ternary operator and implicit array typing.
Depending on includeUniversals, cdParams will be an array with two values in it, namely pageDictionary[pageName] and pageDictionary[CNNService.UniversalPage.Name] - OR, it will be an array with one value in it, namely pageDictionary[pageName].

How to convert one type to another using reflection?

I have a two types that are very similar (i.e. the member names are very similar).
Is there an elegant way to copy one type to another, without having to copy each individual member by hand?
Update
Here is some sample source code:
main()
{
FromCsvFile x = new FromCsvFile(fileName);
OptionsEnt y = x.ToOptionsEnt(); // See helper function below.
}
// Chained helper function to convert type "FromCsvFile" to type "OptionsEnt".
// Want to replace this with something more elegant (perhaps with reflection?).
// Notice the corner cases, i.e. the "ExpirationDate" is a special conversion.
public static OptionsEnt ToOptionsEnt(this FromCsvFile fromCsvFile)
{
return new OptionsEnt
{
Last = fromCsvFile.Last,
Ask = fromCsvFile.Ask,
Bid = fromCsvFile.Bid,
Delta = fromCsvFile.Delta,
EODsnapshotNewYorkTime = fromCsvFile.EODsnapshotNewYorkTime,
Exchange = fromCsvFile.Exchange,
ExpirationDate = fromCsvFile.Expiration.ToTypeIceDate(),
Gamma = fromCsvFile.Gamma,
IV = fromCsvFile.IV,
LastDate = fromCsvFile.Date.ToTypeIceDate(),
AdjustedStockClose = fromCsvFile.AdjustedStockClose,
MeanPrice = fromCsvFile.MeanPrice,
OptionType = fromCsvFile.OptionType == "C" ? OptionTypeEnum.enCall : OptionTypeEnum.enPut,
OpenInterest = fromCsvFile.OpenInterest,
Rho = fromCsvFile.Rho,
StockSymbol = fromCsvFile.SymbolStock,
StrikePrice = fromCsvFile.StrikePrice,
Symbol = fromCsvFile.Symbol,
StockPriceForIV = fromCsvFile.StockPriceForIV,
Star = fromCsvFile.Star,
Theta = fromCsvFile.Theta,
Vega = fromCsvFile.Vega,
Volume = fromCsvFile.Volume,
IVnotInterpolated = fromCsvFile.IVnotInterpolated
};
}
Update
Decided to go with AutoMapper.
Here is the code that replaces all of the code above (assuming that all member names are of the same name and type):
main()
{
FromCsvFile x = new FromCsvFile(fileName);
OptionsEnt y = Mapper.Map<FromCsvFile, OptionsEnt>(x);
}
As we need some custom converters (i.e. DateTime >> IceDateTime), here is the extra line of code that includes a custom mapping for the parameter "ExpirationDate". Adding this line avoids an exception being thrown as it doesn't know how to convert dates from one format to another.
Mapper.CreateMap<DateTime, typeIceDate>().ConvertUsing(ConverterIceTypeIceDate.ToTypeIceDate);
Maybe Automapper?
For example:
Mapper.CreateMap<FromCsvFile, OptionsEnt >();
return Mapper.Map<FromCsvFile, OptionsEnt>(fromCsvFile);
Use something like AutoMapper for that. It will allow you to simply define that class OptionsEnt should be mapped to FromCsvFile and if they have the properties with same names and types then you won't need to define anything else.
Otherwise you'll have to iterate by properties.
See Copyable: A framework for copying or cloning .NET objects. Its slightly slower (it uses reflection), but it has one advantage: you can alter the source to handle corner cases where the member variables need a little bit of work to convert.
For example, in the sample source code in the question, member variable "ExpirationDate" is of type "DateTime" in one type, and type "IceDateTime" in the other (you need to convert the date format with the extension method .ToDateTime).
Here is the source (see the original blog entry for more source):
// Modification to original source code.
Type type = instance.GetType();
if (instance.GetType().Name == "DataTable")
{
// Added to handle custom type.
DataTable dt = (DataTable)instance;
copy = dt.Copy();
}
else if (instance.GetType().Name == "DataSet")
{
// Added to handle custom type.
DataSet ds = (DataSet)instance;
copy = ds.Copy();
}
else
{
// This is the original source.
while (type != null)
{
foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
object value = field.GetValue(instance);
if (visited.ContainsKey(value))
field.SetValue(copy, visited[value]);
else
field.SetValue(copy, value.Clone(visited));
}
type = type.BaseType;
}
}
return copy;

Categories