Within C# is it possible to create a new function on the fly to define a variable?
I know that
string getResult() {
if (a)
return "a";
return "b";
}
String result = getResult();
is possible, but I'm looking for something like
String result = new string getResult() {
if (a)
return "a";
return "b";
}
Is this possible? If so, would someone demonstrate?
EDIT
It is possible
Edit: Final - Solution
This is the end result of what I barbarically hacked together
Func<string> getResult = () =>
{
switch (SC.Status)
{
case ServiceControllerStatus.Running:
return "Running";
case ServiceControllerStatus.Stopped:
return "Stopped";
case ServiceControllerStatus.Paused:
return "Paused";
case ServiceControllerStatus.StopPending:
return "Stopping";
case ServiceControllerStatus.StartPending:
return "Starting";
default:
return "Status Changing";
}
};
TrayIcon.Text = "Service Status - " + getResult();
One way to define such a function:
Func<bool, string> getResult = ( a ) => {
if (a)
return "a";
return "b";
}
You can then invoke: string foo = getResult( true );. As a delegate, it can be stored/passed and invoked when needed.
Example:
string Foo( Func<bool, string> resultGetter ){
return resultGetter( false );
}
You can also close around variables within scope:
bool a = true;
Func<string> getResult = () => {
if (a)
return "a";
return "b";
}
string result = getResult();
You want to use the inline if statement.
string result = a ? "a" : "b";
If you really want inline you can make an extension method for type String:
static class StringExtensions {
public static string ExecuteFunc(
this string str,
Func<string, string> func
) {
return func(str);
}
}
And then, when you want to use it, you do so like so:
string str = "foo";
string result = str.ExecuteFunc( s => {
switch(s){
case "a":
return "A";
default:
return "B";
}
}
);
Not sure what the scope of the variable a is in your example, but assuming that it is accessible within the scope (as it is in your example):
Func<string> getResult = () =>
{
return a ? "a" : "b";
}
Based on the solution you posted, here is a better way to do this.
Change your ServiceControllerStatus enum to add [Description] attributes:
public enum ServiceControllerStatus
{
[Description("Running")]
Running,
// ... others
}
Add the following extension method in a new static class:
public static string ToDescription(this Enum value)
{
var attributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : value.ToString();
}
Now you can simply write:
TrayIcon.Text = "Service Status - " SC.Status.ToDescription();
Related
I do:
(bool success, string name1, string name2) MyFunc() {
if (DateTime.Now.Year > 2020) return (false, "", ""); // error
return (true, "some value", "some value");
}
My coding style is to try and deal with errors first, I tried:
void f() {
if (MyFunc() is (false, var name1, var name2)) return;
Console.WriteLine(name1);
}
I get
Error CS0165 Use of unassigned local variable 'name1'
in the Console.WriteLine
This works:
void f() {
if (!(MyFunc() is (true, var name1, var name2)))) return;
Console.WriteLine(name1);
}
I am trying to understand why this is so ? since MyFunc() is called, the result tuple is available, why doesn't the compiler assign it and let me use it ?
This would have been an extremely useful way of returning status+result, is there a point in requesting that feature ?
name1 and name2 will only be assigned if return value MyFunc() matches the pattern. And, in that case, the method returns.
So, Console.WriteLine(name1); will only be executed if MyFunc() doesn't match the pattern. And, in that case, name1 and name2 won't be assigned.
This will work:
void f()
{
(var error, var name1, var name2) = MyFunc();
if (error) return;
Console.WriteLine(name1);
}
C# variables definite assignment
Pattern Matching
The is type pattern expression
when clauses in case expressions
Update
The syntax in this question isn't easy to read so I got confused. Deconstruction is performed as needed, only after the a successful match. This Sharplab.io example shows that this :
void f() {
if (MyFunc() is (false, var name1, var name2)) {
Console.WriteLine(name1);
return;
}
}
Is converted to this in Release mode:
private void f()
{
ValueTuple<bool, string, string> valueTuple = MyFunc();
if (!valueTuple.Item1)
{
string item = valueTuple.Item2;
Console.WriteLine(item);
}
}
Instead of trying to check for failure, check for success and use the variables :
void f() {
if (MyFunc() is (true, var name1, var name2)) {
Console.WriteLine(name1);
}
}
Or widen the scope, by using a variable outside the block :
var (success,name1,name2)= MyFunc();
if (!success) return;
Console.WriteLine(name1);
Or use switch statements :
switch(MyFunc()) {
case (false, _,):
return ;
case (success, var name1,var name2):
Console.WriteLine(name1);
break;
}
You can also define individual variables and take advantage of the fact that assignments are expressions, but that gets ugly :
bool success;
string name1;
string name2;
if ( ((success,name1,name2)=MyFunc()) is (false,_,_)) {
return;
}
Console.WriteLine(name1);
your bool variable is not instanciated, while strings do.
try this:
static (bool success, string name1, string name2) MyFunc()
{
if (DateTime.Now.Year > 2020) return (false, "", "");
return (true, "some value", "some value");
}
static void f()
{
if (MyFunc() is var (b, name1,name2) && !b) return;
Console.WriteLine(name1);
}
public static void Main()
{
f();
}
I have been working on refactoring some code and then i make something like this. Main idea is that i have couple Methods which contains implementations and they change referenced string variable name in my case.
What i don't like here is situation that in every if statement returning same variable (but with different result).
So my question does someone have better idea for eventually refactoring this? Is there any problem doing this in if statements (from logical, clean code side etc).
All my methods have ref keyword (for string variable name). Sorry for confusion!
private string GenerateNameFrom(IRow row)
{
string name = string.Empty;
if (Method1(name,row))
return name;
else if (Method2(name,row))
return name;
else if (Method3(name,row))
return name;
else return "Null";
}
Here is one way to do it:
private string GenerateNameFrom(IRow row)
{
var name = "";
return (Method1(ref name) || Method2(ref name) || Method3(ref name)) ? name : "Null";
}
Using var to instantiate the empty string, no need to write string twice.
Using || means that the first method that returns true will satisfy the condition and no other method will be executed.
Using the ?: operator for conditional return.
Note: As Matthew Watson commented, you are probably missing the ref (or out keyword - because even though a string is a reference type, it's also immutable, so if you want your methods to effect the content of the name argument, you must either send it as ref or as out, since the only way to change it's value is to assign a new string to it.
(also converted the String.Empty to "", but that's just personal preference)
The variable name will always have an empty string. as you declare and initialize just before if statement
Any how below the short way to get the same result. The Result will be same of the below code and your code:
if (Method1(name) || Method2(name) || Method3(name))
{
return name;
}
else
{
return "Null";
}
Or more specifically using ternary operator
(Method1(name) || Method2(name) || Method3(name)) ? name : "Null";
Can't see the implementation of your methods but I'm assuming something like:
public bool Method1(ref string name)
{
if (condition)
{
name = "SomeValue";
return true;
}
return false;
}
You could refactor those methods to return the updated name:
public string Method1(name)
{
if(condition)
{
return "SomeValue";
}
return null;
}
And then you could just null coalesce the method calls:
private string GenerateNameFrom(IRow row)
{
string name = string.Empty;
return Method1(name)
?? Method2(name)
?? Method3(name)
?? "Null";
}
Well all of this Method1(name) and Method2(name) doing some validation over the input string name and returning bool. In that case would suggest you to combine all those validation logic inside single method using a switch statement probably and use that method instead
I would try to avoid using ref in this case. Instead, you could make the various methods return a tuple (bool success, string value) like so:
public static (bool success, string value) Method1(string name)
{
if (name == "test")
return (true, "changed");
return (false, null);
}
public static (bool success, string value) Method2(string name)
{
if (name == "test")
return (true, "changed");
return (false, null);
}
public static (bool success, string value) Method3(string name)
{
if (name == "test")
return (true, "changed");
return (false, null);
}
Then you can write the calling code like so (it's not shorter, but it avoids ref). Whether you like this better is probably a matter of taste...
private string GenerateNameFrom(/*IRow row*/)
{
string name = string.Empty;
var result = Method1(name);
if (result.success)
return result.value;
result = Method2(name);
if (result.success)
return result.value;
result = Method3(name);
if (result.success)
return result.value;
return null;
}
Alternatively, if null can be used to indicate "no result" then just do a similar thing but checking the return value for null:
private string GenerateNameFrom(/*IRow row*/)
{
string name = string.Empty;
var result = Method1(name);
if (result != null)
return result;
result = Method2(name);
if (result != null)
return result;
return Method3(name);
}
public static string Method1(string name)
{
if (name == "test")
return "changed";
return null;
}
public static string Method2(string name)
{
if (name == "test")
return "changed";
return null;
}
public static string Method3(string name)
{
if (name == "test")
return "changed";
return null;
}
Any suggestion how to make the below query more "readable"?
var result = result
.OrderBy(a =>
(conditionA) ?
valueA :
(conditionB ? valueB :
(conditionC ?
(conditionD ?
valueC : valueD) :
valueE)));
Its difficult to read with the long code of condition and value.
There are several ways of improving the readability of your code.
Indentation
One way is to indent the code in a slightly different way, but this only helps readability a little:
var result = result.OrderBy(a =>
conditionA ? valueA :
conditionB ? valueB :
conditionC ? conditionD ? valueC :
valueD :
valueE);
if, else
You could also turn those ternary operators into a more readable chain of if, else.
var result = Result.OrderBy(a => {
if (conditionA)
{
return valueA;
}
else if (conditionB)
{
return valueB;
}
else if (conditionC)
{
if (conditionD)
{
return valueC;
}
else
{
return valueD;
}
}
else
{
return valueE;
}
});
IComparer<>
One option would be to write your own implementation of IComparer<> and pass it to the OrderBy method. I don't know what type your object is or what type the keys are in your code, so I'm going to assume string keys.
public class MyClassComparer : IComparer<MyClass>
{
public int Compare(MyClass x, MyClass y)
{
string xKey = getKey(x);
string yKey = getKey(y);
return string.Compare(xKey, yKey);
}
private string getKey(MyClass item)
{
if (item.conditionA)
{
return item.valueA;
}
else if (item.conditionB)
{
return item.valueB;
}
else if (item.conditionC)
{
if (item.conditionD)
{
return item.valueC;
}
else
{
return item.valueD;
}
}
else
{
return item.valueE;
}
}
}
Extension method
A final option would be to move your code to an extension method:
public static class MyClassExtensions
{
public static string GetSortingKey(this MyClass item)
{
if (item.conditionA)
{
return item.valueA;
}
else if (item.conditionB)
{
return item.valueB;
}
else if (item.conditionC)
{
if (item.conditionD)
{
return item.valueC;
}
else
{
return item.valueD;
}
}
else
{
return item.valueE;
}
}
}
Using the last option, your call to OrderBy is simply:
result.OrderBy(a => a.GetSortingKey())
I have an array
public static string[] commands =
{
"command1",
"command2",
"command3",
"command4",
"command5",
"command6",
"command7"
};
I want to use the array in the function
public static bool startCommand (string commandName) {
//stuff
if (commandName == commands[0]) {
//stuff
return true;
}
else {
//stuff
switch (commandName) {
case commands [1]:
//stuff
break;
case commands [2]:
//stuff
break;
case commands [3]:
//stuff
break;
case commands [4]:
//stuff
break;
case commands [5]:
//stuff
break;
case commands [6]:
//stuff
break;
default:
return false;
}
//do stuff
return true;
}
}
The error that this is giving me is "A constant value is expected" for each of the cases.
I could use if and else statements, but I think the switch statement looks better for this.
Unless I've missed my mark, my array is of constant strings, so this should work. Any help would be appreciated. Sorry if this is a newb question, I've been programming with C# for about four days.
What you're looking for is the Dictionary<TKey, TValue> type. A Dictionary is basically a collection of Key-Value pairs, something we can take advantage of for what you're attempting to achieve.
Using the example you've given, the implementation would look like this:
Dictionary<string, Action> commandsDictionary = new Dictionary<string, Action>();
commandsDictionary.Add("Command1", () => Console.WriteLine("Command 1 invoked"));
commandsDictionary.Add("Command2", () => Console.WriteLine("Command 2 invoked"));
commandsDictionary["Command2"].Invoke();
// Command 2 invoked
As you'll have noticed, I've introduced the an Action delegate without any parameters.
To introduce a parameter, just specify it as a type argument, like this: Action<int>
Dictionary<string, Action<int>> commandsDictionary = new Dictionary<string, Action<int>>();
commandsDictionary.Add("Command1", (i) => Console.WriteLine("Command {0} invoked", i));
commandsDictionary["Command1"].Invoke(1);
// Command 1 invoked
If you want to return a value from the delegate you're invoking, use the Func delegate, an easy to remember rule with Func is that the last type parameter is always the type being returned, so Func<int, string> would be equivalent to a method with the following signature public string Foo(int i)
Dictionary<string, Func<int, string>> commandsDictionary = new Dictionary<string, Func<int, string>>();
commandsDictionary.Add("Command1", (i) => { return string.Format("Let's get funky {0}", i); });
string result = commandsDictionary["Command1"].Invoke(56963);
Console.WriteLine (result);
// Let's get funky 56963
Reference
I've added this section to aid those who do not yet know what a delegate is... it's all actually rather simple.
Delegates
A Delegate is a Type that represents references to methods. They're just like variables that you declare to reference objects, except instead of objects, they reference methods.
A delegate can be instantiated with a named method or an anonymous function such as a lambda expression (which is the type I've demonstrated above).
The Action Delegate
The Action Delegate has a return type of void and defines its signature with type parameters.
void Example()
{
// Named method
this.NamedActionDelegate = NamedMethod;
this.NamedActionDelegate.Invoke("Hi", 5);
// Output > Named said: Hi 5
// Anonymous Function > Lambda
this.AnonymousActionDelegate.Invoke("Foooo", 106);
// Output > Anonymous said: Foooo 106
}
public Action<string, int> NamedActionDelegate { get; set; }
public Action<string, int> AnonymousActionDelegate = (text, digit) => Console.WriteLine ("Anonymous said: {0} {1}", text, digit);
public void NamedMethod(string text, int digit)
{
Console.WriteLine ("Named said: {0} {1}", text, digit);
}
The Func Delegate
The Func Delegate is similar to the Action Delegate the difference being that Func never returns void and thus will always require at least 1 type argument and as mentioned earlier, the type argument specified last dictates the return type of the delegate.
void Example()
{
// Named method
this.NamedFuncDelegate = NamedMethod;
string namedResult = this.NamedFuncDelegate.Invoke(5);
Console.WriteLine (namedResult);
// Output > Named said: 5
// Anonymous Function > Lambda
string anonyResult = this.AnonymousFuncDelegate.Invoke(106);
Console.WriteLine (anonyResult);
// Output > Anonymous said: 106
}
public Func<int, string> NamedFuncDelegate { get; set; }
public Func<int, string> AnonymousFuncDelegate = (digit) => { return string.Format("Anonymous said: {0}", digit); };
public string NamedMethod(int digit)
{
return string.Format ("Named said: {0}", digit);
}
If you want to use the switch with the array commands, instead use of compare with the items of commands use the index statement like this:
public static string[] commands =
{
"command1",
"command2",
"command3",
"command4",
"command5",
"command6",
"command7"
};
public static bool startCommand(string commandName)
{
var index = Array.IndexOf(commands, commandName);
//stuff
if (index == 0) // commands[0]
{
//stuff
return true;
}
else
{
//stuff
switch (index)
{
case 1: // commands[0]
//stuff
break;
case 2: // commands[2]
//stuff
break;
case 3: // commands[3]
//stuff
break;
case 4: // commands[4]
//stuff
break;
case 5: // commands[5]
//stuff
break;
case 6: // commands[6]
//stuff
break;
default:
return false;
}
//do stuff
return true;
}
}
To summarize as an answer, change it to something like this:
Dictionary<string, Action> commands = new Dictionary<string,Action>();
commands.Add("command1", () => {});
commands.Add("command2", () => { });
commands.Add("command3", () => { });
Action action = null;
commands.TryGetValue(commandName, out action);
if (action != null)
action();
You can make your dictionary static, or possibly readonly if you want:
static void Command1() { }
static void Command2() { }
static readonly Dictionary<string, Action> commands = new Dictionary<string, Action>(){
{ "command1", Command1 },
{ "command2", Command2 }
};
Assuming you are ok with constant strings, what about defining a static class:
public static class COMMANDS
{
public const string COMMAND1 = "command1";
public const string COMMAND2 = "command2";
public const string COMMAND3 = "command3";
public const string COMMAND4 = "command4";
public const string COMMAND5 = "command5";
public const string COMMAND6 = "command6";
public const string COMMAND7 = "command7";
}
and then use it with the switch statement:
//stuff
if (commandName == COMMANDS.COMMAND1)
{
//stuff
return true;
}
else
{
//stuff
switch (commandName)
{
case COMMANDS.COMMAND2:
//stuff
break;
case COMMANDS.COMMAND3:
//stuff
break;
case COMMANDS.COMMAND4:
//stuff
break;
case COMMANDS.COMMAND5:
//stuff
break;
case COMMANDS.COMMAND6:
//stuff
break;
case COMMANDS.COMMAND7:
//stuff
break;
default:
return false;
}
//do stuff
return true;
}
using System;
using System.Reflection;
namespace CommandExample
{
class Program
{
static void Main()
{
var cmdName = "Command1";
// Create an instance of the command class using reflection
Type type = Assembly.GetExecutingAssembly().GetType("CommandExample." + cmdName);
if (type == null) { /* Cannot find command. Handle error */ }
var cmd = Activator.CreateInstance(type) as ICommand;
cmd.Exec();
}
}
interface ICommand
{
void Exec();
}
class Command1 : ICommand
{
public void Exec()
{
Console.WriteLine("Executing Command1");
}
}
}
So we have ternary operators. Great! Then there's the ?? operator, which does a coalesce over a nullable variable.
Example:
string emptyIfNull = strValue ?? "";
Question: Is it possible to implement a simple operator like this for a try-catch?
Example:
string result = CoalesceException(someExpression, "");
public static T CoalesceException<T>(expression, defaultValue)
{
try
{
return evaluate expression; // ?
}
catch
{
return defaultValue;
}
}
Is it possible to implement a method that can be used as easily as possible, or even some kind of coalesce-like operator?
You can:
public static T CoalesceException<T>(Func<T> func, T defaultValue = default(T))
{
try
{
return func();
}
catch
{
return defaultValue;
}
}
but I'm not sure this is what you want...
use:
string emptyIfError = CoalesceException(() => someExpressionThatReturnsAString, "");
for example...
string shortString = null;
string emptyIfError = CoalesceException(() => shortString.Substring(10), "");
will return "" instead of NullReferenceException
important
The function, as written, will cause the "evaluation" of defaultValue always. Meaning:
string Throws() { throw new Exception(); }
string str1 = somethingTrue == true ? "Foo" : Throws();
Here an exception won't be thrown, because Throws() won't be evalued. The same happens with the ?? operator.
string str2 = CoalesceException(() => ((string)null).ToString(), Throws());
This will cause an exception before entering in CoalesceException. Solution:
public static T CoalesceException<T>(Func<T> func, Func<T> defaultValue = null)
{
try
{
return func();
}
catch
{
return defaultValue != null ? defaultValue() : default(T);
}
}
Use:
string emptyIfError = CoalesceException(() => someExpressionThatReturnsAString, () => "");
Here a little something that I've end up, to create a One Liner TryCatch
Usage
var r = Task.TryCatch(() => _logic.Method01(param1, param2));
TryCatch definition
public static class Task
{
public static TResult TryCatch<TResult>(Func<TResult> methodDelegate)
{
try
{
return methodDelegate();
}
catch (Exception ex)
{
// .. exception handling ...
}
return default(TResult);
}
}