I have an enum which I want to present as string using special way:
public enum FailureDescription
{
MemoryFailure,
Fragmentation,
SegmentationFault
}
I want to print the value of that enum as following : FailureDescription.MemoryFailure.ToString() - > Memory Failure
Can I do that ? How? Implement ToString?
You can write own extension method:
public static string ToFormattedText(this MyEnum value)
{
var stringVal = value.ToString();
var bld = new StringBuilder();
for (var i = 0; i < stringVal.Length; i++)
{
if (char.IsUpper(stringVal[i]))
{
bld.Append(" ");
}
bld.Append(stringVal[i]);
}
return bld.ToString();
}
If you want method available for all enums, just replace MyEnum with Enum.
Usage:
var test = MyEnum.SampleName.ToFormattedText();
Consider caching - building string everytime could not be efficient.
Use the Description attribute to decortate your enumeration values. I'd suggest adding a resx file for resources so that you can localise more easily. If you hardcoded "Memory Failure", it becomes more work to be able to change that to another language (as Hans Passant mentioned in the comments).
public enum FailureDescription
{
[Description("Memory Failure")] //hardcoding English
MemoryFailure,
[Description(MyStringsResourceFile.FragmentationDescription)] //reading from a resx file makes localisation easier
Fragmentation,
[Description(MyStringsResourceFile.SegmentationFaultDescription)]
SegmentationFault
}
You can then create a method, or extension method (as shown) to read the Description value.
public static class Extensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fi.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
}
Then call the method like so
Console.WriteLine(FailureDescription.MemoryFailure.GetDescription());
This extension method will do it for you:
public static string ToFormattedText(this FailureDescription value)
{
return new string(value.ToString()
.SelectMany(c =>
char.IsUpper(c)
? new [] { ' ', c }
: new [] { c })
.ToArray()).Trim();
}
You also can use a simple regex & linq mixture to extract and concatenate the words:
var withSpaces =
Regex
.Matches(
FailureDescription.MemoryFailureTest.ToString(),
#"([A-Z][a-z]+)(?=[A-Z]|$)")
.Cast<Match>()
.Select(m => m.Groups[1].Value)
.Aggregate((str, next) => (str = str + " " + next));
DEMO at ideone.com
where:
([A-Z][a-z]+)(?=[A-Z]|$)
matches words that begin with upper-case letters until the next upper-case letter or the end of string is found: DEMO at regex101
.Select(m => m.Groups[1].Value)
selects the matched values from the group 1
.Aggregate((str, next) => (str = str + " " + next));
concatenates words and inserts a space between them.
Here is one of the utilities I've been using. #HansPassant in his comment raised a good point about localizing.
This code takes Resource files into consideration. In the attribute with two params first param is the Key in Resource file, where as the second param is the namespace for the resource.
Checkout the git repo https://github.com/seanpaul/EnumExtensions
public enum TestEnum
{
//You can pass what ever string value you want
[StringValue("From Attribute")]
FromAttribute = 1,
//If localizing, you can use resource files
//First param is Key in resource file, second is namespace for Resources.
[StringValue("Test", "EnumExtensions.Tests.Resources")]
FromResource = 2,
//or don't mention anything and it will use built-in ToString
BuiltInToString = 3
}
[Test ()]
public void GetValueFromAttribute ()
{
var testEnum = TestEnum.FromAttribute;
Assert.AreEqual ("From Attribute", testEnum.GetStringValue ());
}
[Test ()]
public void GetValueFromResourceFile ()
{
var testEnum = TestEnum.FromResource;
Assert.AreEqual ("From Resource File", testEnum.GetStringValue ());
}
An elegant solution following the DRY and KISS principles would be using Humanizer:
"Memory Failure".DehumanizeTo<EnumUnderTest>(); // Returns FailureDescription.MemoryFailure.
"Fragmentation".DehumanizeTo<EnumUnderTest>(); // Returns FailureDescription.Fragmentation.
"Segmentation Fault".DehumanizeTo<EnumUnderTest>(); // Returns FailureDescription.SegmentationFault.
Related
How can I get NDesk to parse multi arg lists at the command line (C#)?
I have two flags that both take multiple parameters (a list of files). So one is -j and the other is -c. But I think NDesk requires each of these parameters to be preceded with the -j/-c)
For instance I want:
%> main -j file1.j file2.j file3.j -c file4.c file5.c file6.c file7.c
And have it produce the 2 lists, one with the .j files and the other with the .c files. But, it expects every file listed this way to be preceded by the flag.
So this will work:
%> main -j file1.j -j file2.j -j file3.j -c file4.c -c file5.c -c file6.c -c file7.c
Though I'd rather have the first version.
Is there a way to do this with the NDesk.Options lib? I've read most of the documentation and I don't think that it is.
There is a way to do this, but it requires little hack. NDesk uses "<>" as a special default handler. What you do is keep track of the "current" parameter and then have the default handler decide what to do with the values based on the current parameter. Here is a sample where I put the values into a dictionary.
static void Main(string[] args)
{
string currentParameter = "";
Dictionary<string, List<string>> parameters = new Dictionary<string, List<string>>();
OptionSet set = new OptionSet() {
{ "c", ".c files", v => currentParameter = "c" },
{ "j", ".j files", v => currentParameter = "j" },
{ "<>", v => {
List<string> values;
if (parameters.TryGetValue(currentParameter, out values))
{
values.Add(v);
}
else
{
values = new List<string> { v };
parameters.Add(currentParameter, values);
}
}
}
};
set.Parse(args);
foreach (var parameter in parameters)
{
Console.WriteLine("Parameter: {0}", parameter.Key);
foreach (var value in parameter.Value)
{
Console.WriteLine("\t{0}", value);
}
}
}
The output is:
Parameter: j
file1.j
file2.j
file3.j
Parameter: c
file4.c
file5.c
file6.c
file7.c
Another way to do this is to override OptionSet.Parse as outlined here
That example describes a more thorough "concatenation/append" approach that will parse all formats, but if you are just interested in handling -flag value1 value2 value3 ... valueN then you can use:
public class MultiOptionSet : OptionSet
{
private string lastArg;
private Option lastOption;
protected override bool Parse(string argument, OptionContext c)
{
// based on example in http://www.ndesk.org/doc/ndesk-options/NDesk.Options/Option.html#M:NDesk.Options.Option.OnParseComplete(NDesk.Options.OptionContext)
string f, n, s, v;
bool haveParts = GetOptionParts(argument, out f, out n, out s, out v);
// reset placeholder for next multiple if we are looking at a flagged argument name
if( haveParts )
{
lastArg = f + n;
}
// are we after a flagged argument name, without parts (meaning a value)
else
{
// remember for next time, in case it's another value
if( null != c.Option ) lastOption = c.Option;
// but if the 'last arg' wasn't already provided, we reuse the one we set last time
else
{
c.Option = lastOption;
c.OptionName = lastArg;
}
c.OptionValues.Add(argument); // add the value to be invoked
c.Option.Invoke(c); // perform the 'setter'
return true;
}
return base.Parse(argument, c);
}
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# - Parse Math Expression
C#, User defined formula
The equation will only use addition, subtraction, multiplication, division operators and will not use brackets. I didn't think it would be so difficult, but I've been thinking about it for hours while trying different things and writing different ideas out.
I thought there might be some way by splitting the string on each of those characters and doing something with the output or by looping through the string character by character and coming up with something, but I'm not clever enough I guess.
Anyways, I'd love to hear other peoples' ideas because I'm stumped. I don't want to use a third-party library of some kind which is what everybody has suggested in old threads that I've been looking at.
For such simple equations it could be implemented with a split and two loops.
For a string like this: "4+5*6/2-8"
Split on operators, keeping them in the result:
"4", "+", "5", "*", "6", "/", "2", "-", "8"
Loop though the operators and calculate multiplication and division, putting the result back in the list:
"4", "+", "30", "/", "2", "-", "8"
"4", "+", "15", "-", "8"
Loop through the operators again and calculate addition and subtraction this time:
"19", "-", "8"
"11"
The easiest way to do that is take advantage of the JIT compiler to evaluate a calculation. Thant's what it's there for. you can even pass in code like Math.Acos(4) to the expression, or "create" a function Acos in the object you are using to allow users not to have to worry about the Math. prefix.
string code = string.Format // Note: Use "{{" to denote a single "{"
(
"public static class Func{{ public static Acos(double d) { return Math.ACos(d); }
public static int func(){{ return {0};}}}}", expression
);
Also you can include additional namespaces if you need any other functions, but Without any extra functions the code is like this:
using System;
using System.Reflection;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
class Program
{
static void Main()
{
TestExpression("2+1-(3*2)+8/2");
TestExpression("1*2*3*4*5*6");
TestExpression("Invalid expression");
}
static void TestExpression(string expression)
{
try
{
int result = EvaluateExpression(expression);
Console.WriteLine("'" + expression + "' = " + result);
}
catch (Exception)
{
Console.WriteLine("Expression is invalid: '" + expression + "'");
}
}
public static int EvaluateExpression(string expression)
{
string code = string.Format // Note: Use "{{" to denote a single "{"
(
"public static class Func{{ public static int func(){{ return {0};}}}}", expression
);
CompilerResults compilerResults = CompileScript(code);
if (compilerResults.Errors.HasErrors)
{
throw new InvalidOperationException("Expression has a syntax error.");
}
Assembly assembly = compilerResults.CompiledAssembly;
MethodInfo method = assembly.GetType("Func").GetMethod("func");
return (int)method.Invoke(null, null);
}
public static CompilerResults CompileScript(string source)
{
CompilerParameters parms = new CompilerParameters();
parms.GenerateExecutable = false;
parms.GenerateInMemory = true;
parms.IncludeDebugInformation = false;
CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp");
return compiler.CompileAssemblyFromSource(parms, source);
}
}
The answer was copied from http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/abff98e3-93fe-44fa-bfd4-fcfe297dbc43/ for I did not like writing the code myself and thanks to Matthew Watson
I didn't have to.
I prefer Recursive Descent Parsing, as stated in a comment. Here is a very quick partial adaptation in C# of the C example found in the linked Wikipedia article.
I find a simple recursive-descent easier to read than the shunting yard method (notice how recursive descent functions closely match EBNF non-terminal definitions) and more extensible. The following can be trivially adapted to allow for parenthesis or "external" functions.
A more robust implementation would actually support symbol classes and handle invalid grammars more gracefully; once again, trivial to add in such a recursive descent parsing setup. Tokening the input (read: splitting the string and converting numbers to double) is left as an exercise to the reader.
class RecDec {
St x; // ugly shared state, it's a quick example
public double eval (params object[] tokens) {
x = new St(tokens);
return expression();
}
double expression() {
double res = term();
string accepted;
while ((accepted = x.acceptOp(new [] {"+", "-"})) != null) {
res = accepted == "+"
? res + term()
: res - term();
}
return res;
}
double term() {
double res = factor();
string accepted;
while ((accepted = x.acceptOp(new [] {"*", "/"})) != null) {
res = accepted == "*"
? res * factor();
: res / factor();
}
return res;
}
double factor() {
var val = x.acceptVal();
if (val == null) {
throw new Exception(x.ToString());
}
return (double)val;
}
}
The "state" / token-feader class:
class St {
IEnumerable<object> src;
public St (IEnumerable<object> src) {
this.src = src;
}
public object acceptVal () {
var first = src.FirstOrDefault();
if (first is double) {
src = src.Skip(1);
return first;
} else {
return null;
}
}
public string acceptOp (params string[] syms) {
var first = src.FirstOrDefault();
if (syms.Contains(first)) {
src = src.Skip(1);
return (string)first;
} else {
return null;
}
}
public override string ToString () {
return "[" + string.Join(",", src.ToArray()) + "]";
}
}
And usage (Dump is a LINQPad extension method, use eval return value as applicable):
void Main()
{
var rd = new RecDec();
// Use results - i.e. Remove Dump - if not on LINQPad
rd.eval(1d, "+", 2d).Dump();
rd.eval(2d, "*", 1d, "+", 2d, "*", 9d, "/", 4d).Dump();
}
I have the following strings:
Actual | Expected
"The Actual String" | "The"
| "Actual"
| "String"
| "Other string"
| ...
I need to create a method that will Assert that any of the Expected strings is contained in the actual string, something like this:
[TestClass]
public class UnitTest
{
[TestMethod]
public void TestMethod()
{
//Assertion Passed
AssertContainsString("The Actual String", "The");
//Assertion Passed
AssertContainsString("The Actual String", "Something", "Actual");
//Assertion Failed
AssertContainsString("The Actual String", "Something", "Something Else");
}
public void AssertContainsString(string actual, params string[] expected)
{
}
}
I tried the CollectionAssert.Contains method but it didn't work. Is there a quick method I can use without iterating into the expected strings?
I think it's possible to use this "StringAssert.Contains(actualString,containsubstring);" in all Framework .NET
It returns true if all the values of expected array is found in actual variable:
bool foundall = expected.Except(actual.Split(' ')).Count()==0;
Return true even if just one value is contained in the actual string:
bool ans = expected.Except(actual.Split(' ')).Count() != expected.Length;
if you did
if (actual.Split(' ').Contains(expected)) return true;
but I think you would still need to iterate the expected's
foreach (string ex in expected)
{
if (actual.Split(' ').Contains(ex)) return true;
}
EDIT as per Gene S comment
expected.Any(ex => actual.Split(' ').Contains(ex))
use the sugar if you want to, but there is no processor savings, it just makes it harder to read.
An extension method for the string class?
public static bool AnyIn(this string s, params string[] values)
{
return values.Any(x => s.Contains(x));
}
callable in this way:
string test = "The actual string";
if(test.AnyIn("The") == true) // success
...
if(test.AnyIn("The", "actual", "string") == true) // success
...
if(test.AnyIn("The", "actual", "value") == true) // success
...
if(test.AnyIn("some", "value") == true) // fail
or also
System.Diagnostics.Debug.Assert(test.AnyIn("some", "value"), "No expected string found"); // fail
of course put the extension method inside a static class
Tried also in Visual Studio 2010 Console Application
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main()
{
string test = "The actual string";
// Prints False
bool result = test.AnyIn("other", "value");
Console.WriteLine(result.ToString());
// Prints True
result = test.AnyIn("other", "The");
Console.WriteLine(result.ToString());
// No Assert dialog here
System.Diagnostics.Debug.Assert(test.AnyIn("other", "The"), "No expected values found");
// Big Assert dialog here with message "No expected values found"
System.Diagnostics.Debug.Assert(test.AnyIn("other", "The"), "No expected values found");
}
}
static class ext
{
public static bool AnyIn(this string s, params string[] values)
{
return values.Any(x => s.Contains(x));
}
}
}
EDIT:
The problem with different case could be resolved changing the extension in this way
public static bool AllIn(this string s, params string[] values)
{
return values.Any(x => s.IndexOf(x + " ", StringComparison.CurrentCultureIgnoreCase) >= 0);
}
but, to prevent false positives when one of expected strings is embedded inside the actual string you need to add a space at the end of the actual string
string test = "The actual string "; // notice the extra space added at the end
What is the most efficient way to parse a C# string in the form of
"(params (abc 1.3)(sdc 2.0)(www 3.05)....)"
into a struct in the form
struct Params
{
double abc,sdc,www....;
}
Thanks
EDIT
The structure always have the same parameters (same names,only doubles, known at compile time).. but the order is not granted.. only one struct at a time..
using System;
namespace ConsoleApplication1
{
class Program
{
struct Params
{
public double abc, sdc;
};
static void Main(string[] args)
{
string s = "(params (abc 1.3)(sdc 2.0))";
Params p = new Params();
object pbox = (object)p; // structs must be boxed for SetValue() to work
string[] arr = s.Substring(8).Replace(")", "").Split(new char[] { ' ', '(', }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < arr.Length; i+=2)
typeof(Params).GetField(arr[i]).SetValue(pbox, double.Parse(arr[i + 1]));
p = (Params)pbox;
Console.WriteLine("p.abc={0} p.sdc={1}", p.abc, p.sdc);
}
}
}
Note: if you used a class instead of a struct the boxing/unboxing would not be necessary.
Depending on your complete grammar you have a few options:
if it's a very simple grammar and you don't have to test for errors in it you could simply go with the below (which will be fast)
var input = "(params (abc 1.3)(sdc 2.0)(www 3.05)....)";
var tokens = input.Split('(');
var typeName = tokens[0];
//you'll need more than the type name (assembly/namespace) so I'll leave that to you
Type t = getStructFromType(typeName);
var obj = TypeDescriptor.CreateInstance(null, t, null, null);
for(var i = 1;i<tokens.Length;i++)
{
var innerTokens = tokens[i].Trim(' ', ')').Split(' ');
var fieldName = innerTokens[0];
var value = Convert.ToDouble(innerTokens[1]);
var field = t.GetField(fieldName);
field.SetValue(obj, value);
}
that simple approach however requires a well conforming string or it will misbehave.
If the grammar is a bit more complicated e.g. nested ( ) then that simple approach won't work.
you could try to use a regEx but that still requires a rather simple grammar so if you end up having a complex grammar your best choice is a real parser. Irony is easy to use since you can write it all in simple c# (some knowledge of BNF is a plus though).
Do you need to support multiple structs ? In other words, does this need to be dynamic; or do you know the struct definition at compile time ?
Parsing the string with a regex would be the obvious choice.
Here is a regex, that will parse your string format:
private static readonly Regex regParser = new Regex(#"^\(params\s(\((?<name>[a-zA-Z]+)\s(?<value>[\d\.]+)\))+\)$", RegexOptions.Compiled);
Running that regex on a string will give you two groups named "name" and "value". The Captures property of each group will contain the names and values.
If the struct type is unknown at compile time, then you will need to use reflection to fill in the fields.
If you mean to generate the struct definition at runtime, you will need to use Reflection to emit the type; or you will need to generate the source code.
Which part are you having trouble with ?
A regex can do the job for you:
public Dictionary<string, double> ParseString(string input){
var dict = new Dictionary<string, double>();
try
{
var re = new Regex(#"(?:\(params\s)?(?:\((?<n>[^\s]+)\s(?<v>[^\)]+)\))");
foreach (Match m in re.Matches(input))
dict.Add(m.Groups["n"].Value, double.Parse(m.Groups["v"].Value));
}
catch
{
throw new Exception("Invalid format!");
}
return dict;
}
use it like:
string str = "(params (abc 1.3)(sdc 2.0)(www 3.05))";
var parsed = ParseString(str);
// parsed["abc"] would now return 1.3
That might fit better than creating a lot of different structs for every possible input string, and using reflection for filling them. I dont think that is worth the effort.
Furthermore I assumed the input string is always in exactly the format you posted.
You might consider performing just enough string manipulation to make the input look like standard command line arguments then use an off-the-shelf command line argument parser like NDesk.Options to populate the Params object. You give up some efficiency but you make it up in maintainability.
public Params Parse(string input)
{
var #params = new Params();
var argv = ConvertToArgv(input);
new NDesk.Options.OptionSet
{
{"abc=", v => Double.TryParse(v, out #params.abc)},
{"sdc=", v => Double.TryParse(v, out #params.sdc)},
{"www=", v => Double.TryParse(v, out #params.www)}
}
.Parse(argv);
return #params;
}
private string[] ConvertToArgv(string input)
{
return input
.Replace('(', '-')
.Split(new[] {')', ' '});
}
Do you want to build a data representation of your defined syntax?
If you are looking for easily maintainability, without having to write long RegEx statements you could build your own Lexer parser. here is a prior discussion on SO with good links in the answers as well to help you
Poor man's "lexer" for C#
I would just do a basic recursive-descent parser. It may be more general than you want, but nothing else will be much faster.
Here's an out-of-the-box approach:
convert () to {} and [SPACE] to ":", then use System.Web.Script.Serialization.JavaScriptSerializer.Deserialize
string s = "(params (abc 1.3)(sdc 2.0))"
.Replace(" ", ":")
.Replace("(", "{")
.Replace(")","}");
return new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize(s);
I have a combo box where I am displaying some entries like:
Equals
Not Equals
Less Than
Greater Than
Notice that these strings contain spaces. I have a enum defined which matches to these entries like:
enum Operation{Equals, Not_Equals, Less_Than, Greater_Than};
Since space is not allowed, I have used _ character.
Now, is there any way to convert given string automatically to an enum element without writing a loop or a set of if conditions my self in C#?
I suggest building a Dictionary<string, Operation> to map friendly names to enum constants and use normal naming conventions in the elements themselves.
enum Operation{ Equals, NotEquals, LessThan, GreaterThan };
var dict = new Dictionary<string, Operation> {
{ "Equals", Operation.Equals },
{ "Not Equals", Operation.NotEquals },
{ "Less Than", Operation.LessThan },
{ "Greater Than", Operation.GreaterThan }
};
var op = dict[str];
Alternatively, if you want to stick to your current method, you can do (which I recommend against doing):
var op = (Operation)Enum.Parse(typeof(Operation), str.Replace(' ', '_'));
Operation enumVal = (Operation)Enum.Parse(typeof(Operation), "Equals")
For "Not Equals", you obv need to replace spaces with underscores in the above statement
EDIT: The following version replaces the spaces with underscores before attempting the parsing:
string someInputText;
var operation = (Operation)Enum.Parse(typeof(Operation), someInputText.Replace(" ", "_"));
Either create a dedicated mapper using a dictionary (per Mehrdad's answer) or implement a TypeConverter.
Your custom TypeConverter could either replace " " -> "_" (and vice versa) or it could reflect the enumeration and use an attribute for determining the display text of the item.
enum Operation
{
[DisplayName("Equals")]
Equals,
[DisplayName("Not Equals")]
Not_Equals,
[DisplayName("Less Than")]
Less_Than,
[DisplayName("Greater Than")]
Greater_Than
};
public class OperationTypeConverter : TypeConverter
{
private static Dictionary<string, Operation> operationMap;
static OperationTypeConverter()
{
BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.GetField
| BindingFlags.Public;
operationMap = enumType.GetFields(bindingFlags).ToDictionary(
c => GetDisplayName(c)
);
}
private static string GetDisplayName(FieldInfo field, Type enumType)
{
DisplayNameAttribute attr = (DisplayNameAttribute)Attribute.GetCustomAttribute(typeof(DisplayNameAttribute));
return (attr != null) ? attr.DisplayName : field.Name;
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
string stringValue = value as string;
if (stringValue != null)
{
Operation operation;
if (operationMap.TryGetValue(stringValue, out operation))
{
return operation;
}
else
{
throw new ArgumentException("Cannot convert '" + stringValue + "' to Operation");
}
}
}
}
This implementation could be improved in several ways:
Make it generic
Implement ConvertTo
Support FlagsAttribute
You can use the Parse method:
Operarion operation = (Operation)Enum.Parse(typeof(Operation), "Not_Equals");
Some examples here
Why use another way : convert Enumeration to String?
Just generate the items of your combo box from your Enumeration.
in C#, you can add extension methods to enum types. See
http://msdn.microsoft.com/en-us/library/bb383974.aspx
You could use this approach to add toString(Operation op), fromString(String str) and toLocalizedString(Operation op) methods to your enum types. The method that you use to lookup the particular string depends on your application and should be consistent with what you do in similar cases. Using a dictionary as others have suggested seems like a good first approach as long as you don't need full localization in your app.
I would use a singleton of this enum mapper class that performs much faster than Enum.Parse (which uses reflection and is really slow).
You can then use EnumFromString(typeof(YourEnum), "stringValue") to get your enum.
As of C# 8 you can do that using switches. In your example I believe the code would be like this.
enum Operation{Equals, Not_Equals, Less_Than, Greater_Than};
public static string OperationString(Operation opString) =>
opString switch
{
Operation.Equals => "Equals",
Operation.Not_Equals => "Not Equals",
Operation.Less_Than=> "Less Than",
Operation.Greater_Than=> "Greater Than",
_ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(opString )),
};
See here for the documentation.