how do I create an enum from a string representation? c# - c#

im trying to pass back from a user control a list of strings that are part of an enum, like this:
<bni:products id="bnProducts" runat="server" ProductsList="First, Second, Third" />
and in the code behid do something like this:
public enum MS
{
First = 1,
Second,
Third
};
private MS[] _ProductList;
public MS[] ProductsList
{
get
{
return _ProductList;
}
set
{
_ProductList = how_to_turn_string_to_enum_list;
}
}
my problem is I dont know how to turn that string into a list of enum, so what should be "how_to_turn_string_to_enum_list"? or do you know of a better way to use enums in user controls? I really want to be able to pass a list that neat

This is a short solution, but it doesn't cover some very important things like localization and invalid inputs.
private static MS[] ConvertStringToEnumArray(string text)
{
string[] values = text.Split(new char[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
return Array.ConvertAll(values, value => (MS)Enum.Parse(typeof(MS), value));
}

You need to look at the System.Enum.Parse method.

Enum.Parse is the canonical way to parse a string to get an enum:
MS ms = (MS) Enum.Parse(typeof(MS), "First");
but you'll need to do the string splitting yourself.
However, your property is currently of type MS[] - the value variable in the setter won't be a string. I suspect you'll need to make your property a string, and parse it there, storing the results in a MS[]. For example:
private MS[] products;
public string ProductsList
{
get
{
return string.Join(", ", Array.ConvertAll(products, x => x.ToString()));
}
set
{
string[] names = value.Split(',');
products = names.Select(name => (MS) Enum.Parse(typeof(MS), name.Trim()))
.ToArray();
}
}
I don't know whether you'll need to expose the array itself directly - that depends on what you're trying to do.

string[] stringValues = inputValue.Split(',');
_ProductList = new MS[stringValues.Length];
for (int i=0;i< stringValues.Length;i++)
_ProductList[i] = (MS) Enum.Parse(typeof(MS), stringValues[i].Trim());
(updated my code because I misread your code)

Mark your enum with the [Flags] attribute, and combine flags instead of an array of enum values.

Related

Minimal API - multi-value parameters separated by commas to array of strings

I have query parameters such as /api/items?sizes=m,l,xxl, meaning they are separated by commas. I want to accept them as array of strings ([FromQuery] string[] sizes).
How do I do that? I know how to split the string, the issue is how do I accept string[] and let make sure it knows how to split the string?
string[] sizes = request.Sizes.Split(",", StringSplitOptions.RemoveEmptyEntries);
Such transformation is not supported even for MVC binders (it will require query string in one of the following formats: ?sizes[0]=3344&sizes[1]=2222 or ?sizes=24041&sizes=24117).
You can try using custom binding:
public class ArrayParser
{
public string[] Value { get; init; }
public static bool TryParse(string? value, out ArrayParser result)
{
result = new()
{
Value = value?.Split(',', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>()
};
return true;
}
}
And usage:
app.MapGet("/api/query-arr", (ArrayParser sizes) => sizes.Value);
Try using %2c in the URL to replace the commas.

How do i split a value in model class

How do i split a value in model class.
in list[0].key = 1 and list[0].value = 1_5
here is the code:
if (data.Things.Count != 0)
{
var ans = new List<QuestionModel>();
ans = data.Things.Select(item =>
{
return new QuestionModel()
{
QuestionId = Convert.ToInt32(item.Key),
AnswerId = Convert.ToInt32(item.Value),
};
}).ToList();
}
here i want to split the value.i.e. in AnswerId want only 5.
If you always want the part after the underscore, and it's always an underscore in the format of item.Value, you can do this:
item.Value.Split('_')[1];
This splits the string on the _ and then takes the second part (e.g. what is after the _).
So the complete line of code would be:
AnswerId = Convert.ToInt32(item.Value.Split('_')[1]),
I would add that the fact you are having to do something this clunky is perhaps a symptom of your model not being a good fit to your domain - if you are able to refactor your model such that you don't have to do this and the field in question contains only the data you are interested in then your solution would be cleaner and more easily maintainable.
Come on. Value is a string value right? Did you look at string class what methods does it have? There is a method called split. Read more here: https://msdn.microsoft.com/en-US/library/b873y76a(v=vs.110).aspx
In short:
string value = "1_5";
string[] arr = value.Split('_');
//now arr[0] is "1" and arr[1] is "5"
int i = Convert.ToInt(arr[1]);
I'm not entirely sure, what you're trying to achieve, but I think you want to split the string "1_5" and retrieve just the "5". This can be achieved using string.Split():
(item.Value.Split('_'))[1]

Get List<String> of only one length when I split String with character array

I use this property to help users filter results, by specifying what shouldn't appear. They can separate their terms with all the characters in INCLUDE_INTERPRET_SEPARATORS. The String is saved to an XML file at startup and close.
However, the List always end up with only 1 index. I wondered for some time whether it had to do with loading the values through XML deserialization, but breakpoints confirmed that the application uses the setters on startup.
After the update, I've confirmed that the splitting will work in a different environment. I still don't know why this code didn't work originally.
_Exclude and Exclude below, are different types on purpose.
private readonly char[] INCLUDE_INTERPRET_SEPARATORS = {';', '|', '+'};
private const string INCLUDE_SEPARATOR = ";";
private List<string> _Exclude = new List<string>();
[DataMember()]
public string Exclude
{
get
{
return String.Join(INCLUDE_SEPARATOR, _Exclude);
}
set
{
string input = Utils.RemoveDiacritics(value);
_Exclude = new List<string>(input.Split(INCLUDE_INTERPRET_SEPARATORS, StringSplitOptions.RemoveEmptyEntries));
onPropertyChanged("Exclude");
}
}
Example
In my XML file I have (amongst other things)
<Episode>9</Episode>
<Exclude>WEB-DL;1080i;MPEG</Exclude>
<FilterEpisode>true</FilterEpisode>
Breakpoints show that Exclude is set to
Index Value Type
[0] "WEB-DL;1080i;MPEG" String
Am I missing something obvious about this?
Update
I made a test on dotnetfiddle and found that the code works in a simplified environment, without DataContractSerializer.
Similarly, when I add an extra property, it works:
private readonly char[] INCLUDE_INTERPRET_SEPARATORS = {';', '|', '+'};
private const string INCLUDE_SEPARATOR = ";";
[IgnoreDataMember()]
public List<string> ExcludeList
{
get
{
return new List<string>(Exclude.Split(INCLUDE_INTERPRET_SEPARATORS, StringSplitOptions.RemoveEmptyEntries));
}
}
private string _Exclude = "";
[DataMember()]
public string Exclude
{
get
{
return _Exclude;
}
set
{
_Exclude = Utils.RemoveDiacritics(value);
foreach (string x in ExcludeList)
{
System.Diagnostics.Debug.WriteLine(x);
}
onPropertyChanged("Exclude");
}
}
Update 2
I figured out what the problem is. INCLUDE_INTERPRET_SEPARATORS is empty when the class object is loaded from XML deserialization. The string doesn't get split. By making fields like these static, they will still be initialized on startup.
Yes, you are missing something. When you set your breakpoint, check the value of _Exclude, not Exclude.

Pass an array to a function (And use the function to split the array)

I want to pass a string array (separated by commas), then use a function to split the passed array by a comma, and add in a delimiter in place of the comma.
I will show you what I mean in further detail with some broken code:
String FirstData = "1";
String SecondData = "2" ;
String ThirdData = "3" ;
String FourthData = null;
FourthData = AddDelimiter(FirstData,SecondData,ThirdData);
public String AddDelimiter(String[] sData)
{
// foreach ","
String OriginalData = null;
// So, here ... I want to somehow split 'sData' by a ",".
// I know I can use the split function - which I'm having
// some trouble with - but I also believe there is some way
// to use the 'foreach' function? I wish i could put together
// some more code here but I'm a VB6 guy, and the syntax here
// is killing me. Errors everywhere.
return OriginalData;
}
Syntax doesn't matter much here, you need to get to know the Base Class Library. Also, you want to join strings apparently, not split it:
var s = string.Join(",", arrayOFStrings);
Also, if you want to pass n string to a method like that, you need the params keyword:
public string Join( params string[] data) {
return string.Join(",", data);
}
To split:
string[] splitString = sData.Split(new char[] {','});
To join in new delimiter, pass in the array of strings to String.Join:
string colonString = String.Join(":", splitString);
I think you are better off using Replace, since all you want to do is replace one delimiter with another:
string differentDelimiter = sData.Replace(",", ":");
If you have several objects and you want to put them in an array, you can write:
string[] allData = new string[] { FirstData, SecondData, ThirdData };
you can then simply give that to the function:
FourthData = AddDelimiter(allData);
C# has a nice trick, if you add a params keyword to the function definition, you can treat it as if it's a function with any number of parameters:
public String AddDelimiter(params String[] sData) { … }
…
FourthData = AddDelimiter(FirstData, SecondData, ThirdData);
As for the actual implementation, the easiest way is to use string.Join():
public String AddDelimiter(String[] sData)
{
// you can use any other string instead of ":"
return string.Join(":", sData);
}
But if you wanted to build the result yourself (for example if you wanted to learn how to do it), you could do it using string concatenation (oneString + anotherString), or even better, using StringBuilder:
public String AddDelimiter(String[] sData)
{
StringBuilder result = new StringBuilder();
bool first = true;
foreach (string s in sData)
{
if (!first)
result.Append(':');
result.Append(s);
first = false;
}
return result.ToString();
}
One version of the Split function takes an array of characters. Here is an example:
string splitstuff = string.Split(sData[0],new char [] {','});
If you don't need to perform any processing on the parts in between and just need to replace the delimiter, you could easily do so with the Replace method on the String class:
string newlyDelimited = oldString.Replace(',', ':');
For large strings, this will give you better performance, as you won't have to do a full pass through the string to break it apart and then do a pass through the parts to join them back together.
However, if you need to work with the individual parts (to recompose them into another form that does not resemble a simple replacement of the delimiter), then you would use the Split method on the String class to get an array of the delimited items and then plug those into the format you wish.
Of course, this means you have to have some sort of explicit knowledge about what each part of the delimited string means.

Parsing formatted string

I am trying to create a generic formatter/parser combination.
Example scenario:
I have a string for string.Format(), e.g. var format = "{0}-{1}"
I have an array of object (string) for the input, e.g. var arr = new[] { "asdf", "qwer" }
I am formatting the array using the format string, e.g. var res = string.Format(format, arr)
What I am trying to do is to revert back the formatted string back into the array of object (string). Something like (pseudo code):
var arr2 = string.Unformat(format, res)
// when: res = "asdf-qwer"
// arr2 should be equal to arr
Anyone have experience doing something like this? I'm thinking about using regular expressions (modify the original format string, and then pass it to Regex.Matches to get the array) and run it for each placeholder in the format string. Is this feasible or is there any other more efficient solution?
While the comments about lost information are valid, sometimes you just want to get the string values of of a string with known formatting.
One method is this blog post written by a friend of mine. He implemented an extension method called string[] ParseExact(), akin to DateTime.ParseExact(). Data is returned as an array of strings, but if you can live with that, it is terribly handy.
public static class StringExtensions
{
public static string[] ParseExact(
this string data,
string format)
{
return ParseExact(data, format, false);
}
public static string[] ParseExact(
this string data,
string format,
bool ignoreCase)
{
string[] values;
if (TryParseExact(data, format, out values, ignoreCase))
return values;
else
throw new ArgumentException("Format not compatible with value.");
}
public static bool TryExtract(
this string data,
string format,
out string[] values)
{
return TryParseExact(data, format, out values, false);
}
public static bool TryParseExact(
this string data,
string format,
out string[] values,
bool ignoreCase)
{
int tokenCount = 0;
format = Regex.Escape(format).Replace("\\{", "{");
for (tokenCount = 0; ; tokenCount++)
{
string token = string.Format("{{{0}}}", tokenCount);
if (!format.Contains(token)) break;
format = format.Replace(token,
string.Format("(?'group{0}'.*)", tokenCount));
}
RegexOptions options =
ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;
Match match = new Regex(format, options).Match(data);
if (tokenCount != (match.Groups.Count - 1))
{
values = new string[] { };
return false;
}
else
{
values = new string[tokenCount];
for (int index = 0; index < tokenCount; index++)
values[index] =
match.Groups[string.Format("group{0}", index)].Value;
return true;
}
}
}
You can't unformat because information is lost. String.Format is a "destructive" algorithm, which means you can't (always) go back.
Create a new class inheriting from string, where you add a member that keeps track of the "{0}-{1}" and the { "asdf", "qwer" }, override ToString(), and modify a little your code.
If it becomes too tricky, just create the same class, but not inheriting from string and modify a little more your code.
IMO, that's the best way to do this.
It's simply not possible in the generic case. Some information will be "lost" (string boundaries) in the Format method. Assume:
String.Format("{0}-{1}", "hello-world", "stack-overflow");
How would you "Unformat" it?
Assuming "-" is not in the original strings, can you not just use Split?
var arr2 = formattedString.Split('-');
Note that this only applies to the presented example with an assumption. Any reverse algorithm is dependent on the kind of formatting employed; an inverse operation may not even be possible, as noted by the other answers.
A simple solution might be to
replace all format tokens with (.*)
escape all other special charaters in format
make the regex match non-greedy
This would resolve the ambiguities to the shortest possible match.
(I'm not good at RegEx, so please correct me, folks :))
After formatting, you can put the resulting string and the array of objects into a dictionary with the string as key:
Dictionary<string,string []> unFormatLookup = new Dictionary<string,string []>
...
var arr = new string [] {"asdf", "qwer" };
var res = string.Format(format, arr);
unFormatLookup.Add(res,arr);
and in Unformat method, you can simply pass a string and look up that string and return the array used:
string [] Unformat(string res)
{
string [] arr;
unFormatLoopup.TryGetValue(res,out arr); //you can also check the return value of TryGetValue and throw an exception if the input string is not in.
return arr;
}

Categories