Is there a way to print all the enums in C# class library or namespace? I want the name to be printed with its values.
For example if I have the namespace as below:
namespace MyCompany.SystemLib
{
public enum ItemStatus
{
None = 0,
Active = 1,
Inactive = 2
}
public enum MyEnum
{
EnumVal1 = 1,
EnumVal2 = 2,
EnumVal3 = 3,
}
}
I would like to print them delimited as below (to a textfile) Bullet given for clarity here not needed in output.
ItemStatus,None=0,Active=1,Inactive=1
MyEnum,EnumVal1=1,EnumVal2=2,EnumVal3
I don't know where to start. Any help is appreciated.
Reflection to the rescue!
List<string> allEnums = new List<string>();
var allTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes());
foreach (Type type in allTypes)
{
if (type.Namespace == "MyCompany.SystemLib" && type.IsEnum)
{
string enumLine = type.Name + ",";
foreach (var enumValue in Enum.GetValues(type))
{
enumLine += enumValue + "=" + ((int)enumValue).ToString() + ",";
}
allEnums.Add(enumLine);
}
}
The first line goes over all assemblies currently loaded in memory (because a namespace can be scattered over many DLLs and EXEs) and filters out those in the right namespace, and that are enums. This can be streamlined into a LINQ query if you'd like.
The inner loop goes over the values of the enum, and uses GetName to match the string to the value.
Try using the Enum.GetNames() method.
It can be done using LINQ and Reflection ofcourse.
var asm = Assembly.LoadFrom("path of the assembly");
var enums = asm.GetTypes().Where(x => x.IsEnum).ToList();
var result = enums
.Select(
x =>
string.Format("{0},{1}", x.Name,
string.Join(",",Enum.GetNames(x)
.Select(e => string.Format("{0}={1}", e, (int)Enum.Parse(x, e))))));
File.WriteAllLines("path", result);
Related
I have the following problem.
I have these strings with whitespace between them.
"+name:string" "+age:int"
I split them with this code:
List<string> stringValueList = new List<string>();
stringValueList = System.Text.RegularExpressions.Regex.Split(stringValue, #"\s{2,}").ToList<string>();
now the elements of List looks like this
"+name:string"
"+age:int"
Now I want to split these strings and create Objects.
This looks like this:
// Storing the created objects in a List of objects
List<myObject> objectList = new List<myObject>();
for(i = 1; i < stringValueList.Count ; i+=2)
{
myObject object = new myObject();
object.modifier = '+';
object.name = stringValueList[i-1].Trim('+'); // out of the example the object.name should be "name"
object.type = stringValueList[i]; // out of the example the object.type value should "string"
objectList.Add(object);
}
At the end I should get two objects with these values:
List<myObject> objectList{ myObject object1{modifier = '+' , name ="name" , type="string"}, myObject object2{modifier='+', name="age" type="int"}}
But my result looks like this:
List<myObject> objectList {myObject object1 {modifier='+', name="name:string" type="+age:int"}}
So instead of getting 2 Objects, I am getting 1 Object. It puts both strings into the elements of the first object.
Can anyone help me out? I guess my problem is in the for loop because i-1 value is the first string in the List and i is the second string but I cant change this.
I guess my problem is in the for loop because i-1 value is the first string in the List and i is the second string but I cant change this.
I don't know why you do i += 2, because apparently you want to split each string in two again. So just have to change that.
Use foreach(), and inside your loop, split your string again:
foreach (var stringValue in stringValueList)
{
myObject object = new myObject();
var kvp = stringValue.Split(':');
object.modifier = '+';
object.name = kvp[0].Trim('+');
object.type = kvp[1];
objectList.Add(object);
}
Of course this code assumes your inputs are always valid; you'd have to add some boundary checks to make it more robust.
Alternatively, you could expand your Regex formula to do the whole thing in one go.
For example, with (?<=")[+](.*?):(.*?)(?="), all you'd have to do is assign the matched group values.
foreach (Match m in Regex.Matches(stringValue, "(?<=\")[+](.*?):(.*?)(?=\")"))
{
myObject obj = new myObject
{
modifier = '+',
name = m.Groups[1].Value,
type = m.Groups[2].Value
};
objectList.Add(obj);
}
It's interesting to see how others approach a problem. I would have done something like this:
public class MyObject
{
public char Modifier { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public static IEnumerable<MyObject> Parse(string str)
{
return str
.Split(' ')
.Where(s => string.IsNullOrEmpty(s) == false)
.ToList()
.ForEach(i =>
{
var sections = i.Remove(0, 1).Split(':');
return new MyObject()
{
Modifier = i[0],
Name = sections[0],
Type = sections[1]
};
});
}
}
I have a list of names. From these, I want to create a new list of lists (or jagged array, if that works better), where the lower-level lists contain variations of the names.
The basic idea is that you take a name and remove one letter at a time to create a list which features all of these creations, plus the original name. So for example, if your names are "bob" and "alice", I want to output
[["bo", "bb","ob","bob"], ["alic", "alie", "alce", "aice", "lice", "alice"]].
I can easily do this for just one name, but I run into problems I can't resolve when I try to create such a nested list (I'm relatively new to C#). Here's a toy example of what I've been trying:
List<string> names = new List<string>()
{
"alice",
"bob",
"curt"
};
//initialize jagged array
string[][] modifiedNames = new string[names.Count][];
//iterate over all names in "names" list
foreach(string name in names)
{
int nameIndex = names.IndexOf(name);
//initialize lower level of array
modifiedNames[nameIndex] = new string[name.Length];
//create variations of a given name
for (int i = 0; i < name.Length; i++)
{
string newName = name.Substring(0, i) + name.Substring(i + 1);
if (modNames[nameIndex].Contains(newName) == false)
modNames[nameIndex].Add(newName);
}
modName.Add(name);
}
I've tried several version thereof, both with lists and arrays, but to no avail. The error message I get in this case is
'string[]' does not contain a definition for 'Add' and no accessible extension method 'Add' accepting a first argument of type 'string[]' could be found (are you missing a using directive or an assembly reference?)
Thanks a lot for your help!
First, that error is telling you that there is no Add() function for an array. As JohnB points out, a List would probably be a better fit here.
Second, I don't like the string[][] anyway. I'd use IDictionary<string, IList<string>>, storing your original name as the key, and the modified names as the value. That way the original and modified versions are stored together and you don't need to cross reference names with modifiedNames (one of which is a List and the other (currently) an array).
IDictionary<string, IList<string>> names = new Dictionary<string, IList<string>>();
names.Add("alice", new List<string>());
names.Add("bob", new List<string>());
names.Add("curt", new List<string>());
foreach (KeyValuePair<string, IList<string>> name in names)
{
for (int i = 0; i < name.Key.Length; i++)
{
string newName = name.Key.Substring(0, i) + name.Key.Substring(i + 1);
if (!name.Value.Contains(newName))
{
name.Value.Add(newName);
}
}
}
Hope this helps.
How about using a list of lists (of string) while you are working in the method and then converting it into an array of array before returning? Or even just returning a list of list, if the return type is not set in stone?
Here is a suggestion:
var names = new List<string>()
{
"alice",
"bob",
"curt"
};
var nameVariations = new List<List<string>>();
foreach (var name in names)
{
var variationsOfName = new List<string>();
for (int i = 0; i < name.Length; i++)
{
var newName = name.Substring(0, i) + name.Substring(i + 1);
if (!variationsOfName.Contains(newName))
{
variationsOfName.Add(newName);
}
}
nameVariations.Add(variationsOfName);
}
return nameVariations.Select(variationsOfName => variationsOfName.ToArray()).ToArray();
Note: for this to compile you'll need to add Linq (using System.Linq;).
I would do this in two steps. First, write a simple method that will get a list of name variations for a single name. We can simplify the code using some System.Linq extension methods, like Select() and ToList(). The Select statement below treats the string as a character array, and for each character t at index i, it selects the substring from name up to that character and adds the substring from name after that character, returning an IEnumerable<string>, which we create a new List<string> from. Then we finally add the original name to the list and return it:
public static List<string> GetNameVariations(string name)
{
var results = name.Select((t, i) =>
name.Substring(0, i) + name.Substring(i + 1, name.Length - (i + 1)))
.ToList();
results.Add(name);
return results;
}
And then we can use this method to get a List<List<string>> of names from a list of names using another method. Here we are calling GetNameVariations for each name in names (which returns a new List<string> for each name), and returning these lists in a new List<List<string>>:
public static List<List<string>> GetNameVariations(List<string> names)
{
return names.Select(GetNameVariations).ToList();
}
In use, this might look like (using your example):
private static void Main()
{
var names = new List<string> {"bob", "alice", "curt"};
foreach (var nameVariations in GetNameVariations(names))
{
Console.WriteLine(string.Join(", ", nameVariations));
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output
You can simplify your logic by using String.Remove(i, 1) to remove one character at a time, iterating over values of i for the length of the string. You can write your query as a one-liner:
var result = names.Select(name => name.Select((_, i) => name.Remove(i, 1)).Reverse().Concat(new[] { name }).ToList()).ToList();
Reformatted for readability:
var result = names
.Select(name =>
name.Select((_, i) => name.Remove(i, 1))
.Reverse()
.Concat(new[] { name })
.ToList())
.ToList();
I think this is a fairly simple way to go:
List<string> names = new List<string>()
{
"alice",
"bob",
"curt"
};
string[][] modifiedNames =
names
.Select(name =>
Enumerable
.Range(0, name.Length)
.Select(x => name.Substring(0, x) + name.Substring(x + 1))
.Concat(new [] { name })
.ToArray())
.ToArray();
That gives:
I have a simple List that each row of it has 50 columns. I want return all 50 columns + 3 custom columns but i want make each row of the list like a flat (not nested) object.
Example:
var newList = list.Select(x => new
{ x,
d.CustomColA = x.ColA+10,
d.CustomColB = x.ColB+30,
d.CustomColC = x.ColC+50
});
Result: It works well but each result row is like an nested object:
var row = newList.FirstOrDefault();
row.x.ColA
row.x.ColB
row.x.ColC
.....
row.CustomColA
row.CustomColB
row.CustomColB
Expected Result:
var row = newList.FirstOrDefault();
row.ColA
row.ColB
row.ColC
.....
row.CustomColA
row.CustomColB
row.CustomColB
I used dynamic type and wrote the following code but it did not return expected result:
var newList = list.Select(x =>
{
dynamic d = x;
d.CustomColA = x.ColA+10;
d.CustomColB = x.ColB+30;
d.CustomColC = x.ColC+50;
return d;
//return x;
});
Result in watch panel: 'newList.FirstOrDefault()' threw an exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'
Update:
Attention: I wrote in my question that i have 50 columns and wrote an
example to show you i do not want name all the columns in the Select!
(I know I can write name of all 53 column in a Select!) So that is not the correct answer.
Attention2: In the real project i have complicated custom columns but i wrote very simple example here to show what i want. Please write your flexible answers. Thank you.
So what you are looking to do is basically map a set of properties. There are libraries for this sort of thing, Automapper is a good one. However, you can also accomplish this yourself with a reflective constructor in an inheriting class. That would look like this:
Assumptions:
Your class with 50 columns is called Cols
You can inherit from Cols
public class CustomColumns : Cols
{
public int CustomColA {
get{
return this.ColA + 10;
}
}
public int CustomColB {
get{
return this.ColB + 30;
}
}
public int CustomColC {
get{
return this.ColC + 50;
}
}
public CustomColumns(Cols cols)
{
string[] localNames = this.GetType().GetMembers().Where(m => m.MemberType == MemberTypes.Property).Select(m => m.Name).ToArray();
string[] ctorNames = cols.GetType().GetMembers().Where(m => m.MemberType == MemberTypes.Property).Select(m => m.Name).ToArray();
string[] names = localNames.Intersect(ctorNames).ToArray();
foreach (string s in names)
{
PropertyInfo propSet = this.GetType().GetProperty(s);
PropertyInfo propGet = typeof(Cols).GetProperty(s);
propSet.SetValue(this, propGet.GetValue(cols, null));
}
}
}
Here is a demo of this working in dotnetfiddle: https://dotnetfiddle.net/AKPYQD
Use an anonymous type within the Select:
var newList = list.Select(x =>
new
{
ColA = x.ColA,
ColB = x.ColB,
ColC = x.ColC,
CustomColA = x.ColA+10;
CustomColB = x.ColB+30;
CustomColC = x.ColC+50;
}).ToList();
The .Select() is creating a new object. Even if you just wrote:
var newList = list.Select(x => new
{ x });
You've get a nested property. You are just going to have to explicitly assign every column to a new property (Do you really need all 50 of them?)
I am trying to make a dynamic linq query that will check for values based on a string.
First of all, here's the query:
objQry = from o in m_Db.OBJECTS.Where(whereConditions)
select o;
if(!objQry.Any())
{
return null;
}
The whereConditions variable is a string I build and pass as parameter to find out the values I need. Here's examples of valid string:
OBJ_NAME == \"Sword\" and OBJ_OWNER == \"Stan\"
This will return any item whose name is "Sword" and owner is "Stan;
OBJ_COLOR == \"Blue\" OR OBJ_COLOR == \"Red\"
This will return any item which color is either blue or red.
Up to there, I'm fine, but now I have a problem: I need to check a decimal field. So I've tried this string:
OBJ_NUMBER == 1
But the query returns null even if there are objects which OBJ_NUMBER value is 1. It's a decimal. How can I indicate the query that they need to check for a decimal value?
**** EDIT ****
I have tried to "modify" the value passed so that it looks like this:
"CARD_NUMBER == Convert.ToDecimal(1)"
And now I have a different kind of error telling me this:
LINQ to Entities does not recognize the method 'System.Decimal ToDecimal(Int32)' method, and this method cannot be translated into a store expression.
Any clues anyone? I'm still looking for a way to do this. Thanks!
EDIT 2
You can get an example of how my code is shaped by looking at this question.
Let's come back at this problem. I want to check decimal values. Let's say that OBJ_NUMBER is a decimal field.
Using Dynamic Linq, I tried to read the decimal field. Say that I want to get each object which number is 1.27. The whereConditions field would then be shaped like this:
OBJ_NUMBER == 1.27
But then I would get an Invalid real literal '1.27' error. I don't know why.
So I have tried Gert Arnold's solution and done this instead:
decimal bDecimal = decimal.Parce(valueToParse);
param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = bDecimal };
valuesToUse.Add("CARD_NUMBER == #cardNumber");
listParams.Add(param);
But I ended up having 2 problems:
The first problem is that my whereConditions string is shaped this way:
CARD_NUMBER == #cardNumber
But I get the following error:
No property or field 'cardNumber' exists in type 'CARD'
Leading me to believe that it cannot make the link between the object parameter and the string used to do the query.
As you can see, I have a list of Params. This is because I cannot know for sure how many parameters the user will chose. So each time the user enters a new search field, I have to create a new ObjectParameter and store it in a list. Here's how I try to do the thing after:
ObjectParameter[] arrayParameters = listParams.ToArray();
// Convert the list to an array
And then, when I try to make the query:
cardQry = from c in mDb.CARD.Where(whereConditions, arrayParameters)
select c;
But to no avail.
RESULTS
Based on the answered question below, I have developped something "awful", yet functional.
First of all, I ignore every decimal fields because I could never reach them with dynamic linq. Instead, I do this:
var valuesToParse = keyValuePair.Value.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
// Here I parse the value and, if that's the case, the symbol.
decimal baseValue = decimal.Parse(valuesToParse[0]);
if (valuesToParse.Count() > 1)
{
string baseMethod = valuesToParse[1];
if (baseMethod == ">" || baseMethod == ">=")
{
if (baseMethod == ">=")
{
baseValue--;
}
// The list is actually like this: Dictionary<string, object> list = new Dictionary<string, object>();
list.Add("low", baseValue);
// I kind of activate a tag telling me that the user is looking for a higher value.
cardHigher = true;
}
else
{
if (baseMethod == "<=")
{
baseValue++;
}
list.Add("low", baseValue);
cardLower = true;
}
}
else
{
//lowParam = new ObjectParameter("dec", typeof(decimal)) { Value = baseValue };
list.Add("low", baseValue);
}
cardNumberActivated = true;
At the end, when I get the list of objects, I do this:
if (list.Count > 0)
{
(example)
if (cardNumberActivated)
{
if (cardHigher)
{
q = mDb.CARD.Where("CARD_NUMBER >= #0", list["low"]).ToList();
}
else if (cardLower)
{
q = mDb.CARD.Where("CARD_NUMBER <= #0", list["low"]).ToList();
}
else
{
q = mDb.CARD.Where("CARD_NUMBER == #0", list["low"]).ToList();
}
}
}
// Here we get the orinalData with the basic filters.
listToReturn.AddRange(cardQry);
if (q != null)
{
//listToReturn.AddRange(q);
for (int i = 0; i < listToReturn.Count; i++)
{
var priceList1 = listToReturn[i];
if (!q.Any(_item => _item.CARD_NUMBER == priceList1.CARD_NUMBER))
{
listToReturn.RemoveAt(i);
i--;
}
}
}
And it works. This is not an elegant way to make it work, but I can validate the fields the way I wanted, and for this, I am thankful at last.
You should not build a query string with inline predicate values. Use parameters in stead. Then will also be able to specify the type:
var whereConditions= "it.CARD_NUMBER = #cardNumber";
var param = new ObjectParameter("cardNumber", typeof(decimal)) { Value = 1 };
objQry = from o in m_Db.OBJECTS.Where(whereConditions, param);
Edit
I don't know what doesn't work in your code. Here's just a random piece of working code derived from one of my own projects:
var param1 = new ObjectParameter("dec", typeof(decimal)) { Value = 90000m };
var param2 = new ObjectParameter("int", typeof(int)) { Value = 90000 };
var q = ValueHolders.Where("it.DecimalValue >= #dec OR it.IntegerValue > #int",
param1, param2).ToList();
Note that param1, param2 could also be an array of ObjectParameter.
I have some class with lots of fields;
public class CrowdedHouse
{
public int value1;
public float value2;
public Guid value3;
public string Value4;
// some more fields below
}
My classmust be (de)serialized into simple Windows text file in the following format
NAME1=VALUE1
NAME2=VALUE2
What is the most convinient way to do that in .NET? This is a text file and all the values must be fist converted to string. Let's assume I have already converted all data to strings.
UPDATE One option would be pinvoke WritePrivateProfileString/WritePrivateProfileString
but these are using the required "[Section]" field that I don't need to use.
EDIT: If you have already converted each data value to strings, simply use the method below to serialize it after making a Dictionary of these values:
var dict = new Dictionary<string, string>
{
{ "value1", "value1value" },
{ "value2", "value2value" },
// etc
}
or use dict.Add(string key, string value).
To read the data, simply split each line around the = and store the results as a Dictionary<string, string>:
string[] lines = File.ReadAllLines("file.ext");
var dict = lines.Select(l => l.Split('=')).ToDictionary(a => a[0], a => a[1]);
To convert a dictionary to the file, use:
string[] lines = dict.Select(kvp => kvp.Key + "=" + kvp.Value).ToArray();
File.WriteAllLines(lines);
Note that your NAMEs and VALUEs cannot contain =.
Writing is easy:
// untested
using (var file = System.IO.File.CreateText("data.txt"))
{
foreach(var item in data)
file.WriteLine("{0}={1}", item.Key, item.Value);
}
And for reading it back:
// untested
using (var file = System.IO.File.OpenText("data.txt"))
{
string line;
while ((file.ReadLine()) != null)
{
string[] parts = line.Split('=');
string key = parts[0];
string value = parts[1];
// use it
}
}
But probably the best answer is : Use XML.
Minor improvement of Captain Comic answer:
To enable = in values: (will split only once)
var dict = lines.Select(l => l.Split(new[]{'='},2)).ToDictionary(a => a[0], a => a[1]);