Foo and Bar enum members share the same associated value of 180:
public enum EnumShareValues
{
Default = 0,
Foo = 180,
Bar = 180,
}
This code prints String representation of 'Bar' is 'Foo' which is correct, it returns the first occurence of value 180:
const EnumShareValues bar = EnumShareValues.Bar;
Debug.WriteLine("String representation of 'Bar' is '{0}'", bar);
But is it somehow possible to get both names for enum item with value of 180?
Something like:
// would in this case return "Foo, Bar"
Enum.GetAllNames(typeof(EnumShareValues), EnumShareValues.Bar, ",");
Edit:
Finally after some testing and fiddling I ended with the following code. Thank you for all your answers!
public static IEnumerable<string> GetAllNames<T>(T propValue)
where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
throw new ArgumentException("T must be an enumerated type");
var allNames = Enum.GetNames(typeof(T))
.Where(name => ((T)Enum.Parse(typeof(T), name)).Equals(propValue));
return allNames;
}
Your enums need to be unique, if you duplicate the id then you end up with the following stored internally - look for the debug window with the values in the collection. I suggest a small refactor of the code to accommodate.
this general-puprose method works (fiddle):
i start from enum names and get corresponding values:
public static class Util
{
public static IEnumerable<string> GetSynonims(this Enum value)
{
Type e = value.GetType();
return Enum.GetNames(e).Where(n => Enum.Parse(e, n).Equals(value));
}
}
usage:
Console.WriteLine(String.Join(", ", EnumShareValues.Bar.GetSynonims()));
prints:
Foo, Bar
There's nothing built in, but you can string a few different methods together easily enough:
var allNames =
Enum.GetNames(typeof (EnumShareValues))
.Where(name => (EnumShareValues)Enum.Parse(typeof (EnumShareValues), name)
== EnumShareValues.Bar);
If we were allowed to restrict generic methods to enums, this would be great to wrap up as a generic helper method. You can, of course, do so, but it will produce runtime errors if you try to use it with a non-enum based type.
Related
Suppose I have a container class that contains two properties:
string contents
bool isCommaSeperated
And a function:
? compute()
{
if(this.isCommaSeperated)
{
return contents.split(",").toList();
}
else
{
return contents;
}
}
Is there a way for this function to return either a string or a list of strings?
Or what type of design would allow me to achieve something similar?
I would just return both results as a collection:
IList<string> compute()
{
if (this.isCommaSeperated)
{
return contents.Split(","); // No need to turn the array into a list
}
return new[] { contents };
}
You can use dynamic to implement that:
dynamic Compute(bool isCommaSeperated)
{
if(isCommaSeperated)
{
return contents.Split(",").ToList();
}
else
{
return contents;
}
}
Code will still preserve type information, but let you return any type you like and fail at run-time if you try to use methods of another type.
Note that you give up compile type safety by doing it. Depending on your needs it may be ok, but consider is some alternative solution that preserve compile type safety would work better. I.e. returning single element array as shown in istme86's asnwer.
While IEnumerable<string> is the standard solution, you could also try the new StringValues struct which implicitly casts between string values and string arrays:
StringValues a = "A";
StringValues b = new string[] { "A", "B" };
StringValues c = null;
Console.WriteLine(a.Contains("A"));
// true
Console.WriteLine(b.Any(x => x == a));
// true
Console.WriteLine(c.Any());
// false
How to skip obsolete values when I'm casting my int values to enums? I have minimum working example below:
using System;
public class Program
{
public static void Main()
{
int valueInt = 1;
var en = (TestObsolete)valueInt;
Console.WriteLine(en);
}
}
enum TestObsolete
{
Undefined,
[Obsolete]
ValueA = 1,
ValueB=1,
}
I'm getting ValueA, but expecting to get ValueB. Especially I'm interested in generic method with following signature:
public static T ParseEnumWithoutObsolete<T>(int val) where T: struct {
I tried to do something like that:
T #enum;
var enumValues = Enum.GetValues(typeof(T)).Cast<T>();
var obsoleteValues = enumValues.Where(a => typeof(T).GetField(a.ToString()).CustomAttributes.Any(t => t is ObsoleteAttribute));
var activeValues = enumValues.Except(obsoleteValues);
but stuck in the next step.
I'm getting ValueA, but expecting to get ValueB.
You're getting the value represented by the integer 1. The fact that you're seeing that as ValueA has nothing to do with Parse, and everything to do with ToString.
It's really, really important to bear in mind that when you have a value of an enum type, it's really just an integer. There can be several names for the same integer value, and they're completely indistinguishable when you've just got the value.
It sounds to me like what you really want to do - possibly in addition to your parsing method - is write a ToStringWithoutObsolete method. That could map values to names, but only for values which don't have the obsolete attribute. Note that using typeof(T).GetField(a.ToString()) anywhere in your code will make the results unpredictable. It would be better to get all the static fields within the enum type. So for example:
var valueToName = typeof(T)
.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
.Where(f => !f.IsDefined(typeof(ObsoleteAttribute), false))
.ToDictionary(f => (T) f.GetValue(null),
f => f.Name);
Good morning.
I have the need to create a little helper class, using generics, however my knowledge of generics is very low.
So here is what i need.
i have defined enums in C#, to have description properties. for example
public enum EnumLineItemErrorCode
{
[Description("None")]
None = 0,
[Description("helpful Desc")]
MissnigA= 1,
[Description("another desc")]
MissingB = 2
}
I also have created helper functions that get he description out of the enums like
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
Now if i need the desc i can call the method like the following
EnumerationsHelper.GetEnumDescription(EnumLineItemErrorCode.MissnigA);
However when we want to do bindinds to a datasource i currently do the following for each value on the enum.
dropdownList.Add(new ListItem(EnumerationsHelper.GetEnumDescription(EnumLineItemErrorCode.MissnigA), EnumLineItemErrorCode.MissnigA.ToString()));
But this approach is inflexible as the enum grows in size and also because it does not automatically adds a value to the list if i just add it to the enum.
So my question is.
Can u create a helper method that will return me a list of Description, Value,
where description is the enum description and the value is the enum internal value.
For example on the code that i have will be used as
object t EnumerationsHelper.GetDescriptionAndValuesAslist(EnumLineItemErrorCode);
and object t is structure of with values <"None",None">,<"MissnigA","helpful Desc">,<"MissingB","another desc">
Thank you in advance.
This will do the job.
private string[] GetEnumDescriptions<T>()
{
return Enum.GetValues(typeof(T))
.Cast<Enum>()
.Select(GetEnumDescription)
.ToArray();
}
Use case:
var descriptions = GetDescriptions<EnumLineItemErrorCode>();
Note: If T is not of type Enum Enum.GetValues method will throw exception.
I quickly wrote the following helper method for you
public static IDictionary<string, string> GetEnumBindings<T>()
{
if (!typeof(Enum).IsAssignableFrom(typeof(T)))
{
throw new ArgumentException("The provided type is not an enum");
}
var result = new Dictionary<string, string>();
var fieldNames = Enum.GetNames(typeof (T));
foreach (var fieldName in fieldNames)
{
var fieldAttributes = typeof (T).GetField(fieldName)
.GetCustomAttributes(typeof (DescriptionAttribute), false);
var description = fieldAttributes.Any()
? ((DescriptionAttribute) fieldAttributes.First()).Description
: fieldName;
result.Add(fieldName, description);
}
return result;
}
And use case is:
var bindings = GetEnumBindings<EnumLineItemErrorCode>();
var listItems = bindings.Select(b => new ListItem(b.Value, b.Key));
After that just add listItems to your DropDownList.
Good luck!
UPD: Since description is not unique, I modified code a little bit to add field name as a key to the dictionary.
This is what you are looking for: Enum.GetValues
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);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I pass an anonymous type to a method?
I have the following LINQ Statement, whose output has to be processed in another method:
var data = from lines in File.ReadAllLines(TrainingDataFile)
.Skip(ContainsHeader ? 1 : 0)
let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
let target = f[TargetVariablePositionZeroBased]
select new { F=f, T=target };
What should be the datatype of the parameter in the method that will take this data?
You can not return the anonymous data types from a method. You can define a class and return object of that class from query and pass it to target method.
public class SomeClass
{
public string F {get; set;}
public string T {get; set;}
}
var data = from lines in File.ReadAllLines(TrainingDataFile)
.Skip(ContainsHeader ? 1 : 0)
let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
let target = f[TargetVariablePositionZeroBased]
select new SomeClass { F=f, T=target };
You can pass the query result IEnumerable<SomeClass> to method as parameter.
public void MethodToCall(IEnumerable<SomeClass> someClass)
{
}
To call the method by passing the query result (IEnumerable<SomeClass>) that is stored in data in this sample code
MethodToCall(data);
You can't very easily pass anonymous types around. You can either create a class, or since your data has only two properties, use a Tuple:
select new Tuple<List<string>, string> (f, target);
If I have the data types correct, then the data type of the parameter would be:
IEnumerable<Tuple<List<string>, string>>
and you would reference F and T using the Tuple properties Item1 and Item2.
1) Just to pass the result of the query, make your function generic, that will do:
var data = from lines in File.ReadAllLines(TrainingDataFile)
.Skip(ContainsHeader ? 1 : 0)
let f = lines.Split(new[] { FieldSeparator }).ToList<String>()
let target = f[TargetVariablePositionZeroBased]
select new { F=f, T=target };
SomeMethod(data);
public void SomeMethod<T>(IEnumerable<T> enumerable)
{
// ^^choose the return type..
}
Simple. If the processing inside the method is something so simple this will do. But you won't be able to access properties F and T inside the method.
To do so:
2) You can use the "cast by example" trick shown here by Eric. To quote him:
We use method type inference and local variable type inference to tell
the compiler "these two things are the same type". This lets you
export an anonymous type as object and cast it back to anonymous type.
...the trick only works if the example and the source objects were
created in code in the same assembly; two "identical" anonymous types
in two different assemblies do not unify to be the same type.
SomeMethod(data);
public void SomeMethod(IEnumerable<object> enumerable)
{
var template = new { F = new List<string>(), T = string.Empty };
foreach (var item in enumerable)
{
var anonymousType = item.CastToTypeOf(template);
//print string.Join(", ", anonymousType.F) + " - " + anonymousType.T //compiles
//or whatever
}
}
//a more generic name perhaps is 'CastToTypeOf' as an extension method
public static T CastToTypeOf<T>(this object source, T example) where T : class
{
return (T)source;
}
The catch here is that SomeMethod now is tailor made for your anonymous type, since you're specifying a specific type inside the method, so its better to not make the function generic (though you can do) and to give a suitable name for the function.
3) If function is just for your unique type now, I would better have them all wrapped in a single method and not pass at all - no hassle! :)
4) Or you can delegate the action to be done on your anonymous type. So method signature would be like:
SomeMethod(data, d => print string.Join(", ", d.F) + " - " + d.T);
public void SomeMethod<T>(IEnumerable<T> enumerable, Action<T> actor)
{
foreach (var item in enumerable)
actor(item);
}
If it matters you can have Func delegate as well by having one more type argument.
5) Rely on fiddly reflection to get the properties from your anonymous type otherwise.
6) Use dynamic keyword on method argument and now you have dynamic typing. Both the above doesnt give you benefits of static typing.
7) You will be better off having a separate class that holds F and T. And that the best of all. But ask yourself do they together represent something as an entity?
8) If not, just pass an IEnumerable<Tuple> or IDictionary depending on what matters.
It all depends on what/how you want to achieve with the method. Personally, I would go for the approach 2 in a hobby project (for the fun involved), but in production code 3, 4, 7, 8 depending on the context.