I was looking at a piece of error handling code that looks like this:
if (condition) {
thereIsAProblem = true;
problemDescription = "x";
}
if (!thereIsAProblem && condition2) {
thereIsAProblem = true;
problemDescription = "y";
}
And I got to wondering whether there is a way to define a local variable called thereIsNotAProblem that is dynamically based on the value of thereIsAProblem. In other words:
var thereIsAProblem = false;
var thereIsNotAProblem = *** some expression... ***
Console.WriteLine(thereIsNotAProblem); // true
thereIsAProblem = true;
Console.WriteLine(thereIsNotAProblem); // false
if (thereIsNotAProblem && condition3) {
..
}
Is there some expression that can be entered on the line above that would assign the value of thereIsNotAProblem to be a dynamic formula based on !thereIsAProblem, and still allow thereIsNotAProblem to be supplied anywhere a bool value is required?
Not quite... but you could make it a delegate instead:
Func<bool> thereIsNotAProblem = () => { /* some expression */ };
Console.WriteLine(thereIsNotAProblem()); // true
thereIsAProblem = true;
Console.WriteLine(thereIsNotAProblem()); // false
Note how now each time was want to evaluate thereIsNotAProblem we invoke the delegate... which evaluates the expression to get a bool value.
Whilst you can do this by declaring a lambda,
var thereIsAProblem = false;
Func<bool> thereIsNotAProblem = () => !thereIsAProblem;
I'd argue you shouldn't. thereIsAProblem and thereIsNotAProblem look very similar and so one could easily be misread for the other. the use of ! to negate a variable with a positive name is well understood and easy to read and should lead to less bugs.
I'd further argue that a better solution is the "fail fast" approach of returning as soon as there is a problem, avoiding the need to test for an earlier problem in the first place:
if (condition)
{
problemDescription = "x";
return;
}
if (condition2)
{
problemDescription = "y";
return;
}
...
You could use do something like the following
(also see on .NET Fiddle https://dotnetfiddle.net/E9X6XJ )
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
Console.WriteLine("YourQuestion() returns " + YourQuestion());
Console.WriteLine("AnswerOne() returns " + AnswerOne());
Console.WriteLine("AnswerTwo() returns " + AnswerTwo());
}
private static bool condition1()
{
return false;
}
private static bool condition2()
{
return true;
}
private static bool condition3()
{
return true;
}
public static string YourQuestion()
{
var thereIsAProblem = false;
var problemDescription = "";
if (condition1()) {
thereIsAProblem = true;
problemDescription = "x";
}
if (!thereIsAProblem && condition2()) {
thereIsAProblem = true;
problemDescription = "y";
}
return problemDescription;
}
public static string AnswerOne()
{
return checkCondition1() ??
checkCondition2() ??
checkCondition3();
}
private static string checkCondition1()
{
return condition1() ? "x" : null;
}
private static string checkCondition2()
{
return condition2() ? "y" : null;
}
private static string checkCondition3()
{
return condition3() ? "z" : null;
}
public static string AnswerTwo()
{
var conditionChecks = new Dictionary<string,Func<bool>>();
conditionChecks.Add("x",condition1);
conditionChecks.Add("y",condition2);
conditionChecks.Add("z",condition3);
foreach (var check in conditionChecks)
{
if (check.Value())
{
return check.Key;
}
}
return null;
}
}
Related
I would like to code a framework in C# Console Application(CLI), details aren't important.
I don't know, how to recognize commands cleanly, and shortly.
I tried with switch-case:
public static void command_recognizing(string command) // random example
{
string[] tmp_array = command.Split(' ');
switch(tmp_array[0])
{
case("help"):
method_library.help(); // no need argument
break;
case("time"):
method_library.time(); // no need argument
break;
case("shutdown"):
method_library.shutdown(tmp_array); // need argument
break;
default:
Console.WriteLine("Error! {0} is not a known command!",tmp_array[0]);
break;
}
}
I also tried if-else:
public static void command_recognizing(string command) // random example
{
string[] tmp_array = command.Split(' ');
if(command.Contains("help"))
{
method_library.help(); // no need argument
}
else if(command.Contains("time"))
{
method_library.time(); // no need argument
}
else if(command.Contains("shutdown"))
{
method_library.shutdown(tmp_array); // need argument
}
else
{
Console.WriteLine("Error! {0} is not a known command!",tmp_array[0]);
}
}
I tried to store the commands in a string array, still the same, long and ugly.
There is any other way, to make the command recognizing shorter, cleaner and easier to modify?
Foregive me for my english. Feel free to correct me!
You could use Reflection to execute methods of a class.
void Main() {
var cmd = new Commands();
while (!cmd.Exitting) {
var cmdline = Console.ReadLine();
var cmdargs = Regex.Split(cmdline.Trim(), #"\s+");
if (!cmd.TryInvokeMember(cmdargs[0], cmdargs.Skip(1).ToArray()))
Console.WriteLine($"Unknown command: {cmdargs[0]}");
}
}
// Define other methods and classes here
public class Commands {
public bool Exitting { get; private set; }
public Commands() {
Exitting = false;
}
public void exit() {
Exitting = true;
}
public int sum(object[] args) {
return args.Select(s => Convert.ToInt32(s)).Sum();
}
public bool TryInvokeMember(string methodName, object[] args) {
var method = typeof(Commands).GetMethod(methodName.ToLower());
if (method != null) {
object res;
if (method.GetParameters().Length > 0)
res = method.Invoke(this, new object[] { args });
else
res = method.Invoke(this, new object[0]);
if (method.ReturnType != typeof(void))
Console.WriteLine(res.ToString());
return true;
}
else
return false;
}
}
I am trying to create a filehelper utility and I am getting issue in assigning Func to an event. It says non assignable.
The event and delegate signature is as below
public event AfterReadHandler<T> AfterReadRecord
public delegate void AfterReadHandler<T>(EngineBase engine, fterReadEventArgs<T> e);
The code is as below
public class FileHelperUtility<T> where T : class
{
public List<T> ParseFile<T>(string fileName, ImportFileError fileError,Func<EngineBase, AfterReadEventArgs<T> > afterReadFunc ) where T : class
{
List<T> records = new List<T>();
var fileEngine = InitializeFileEngine<T>(afterReadFunc);
records = fileEngine.ReadFile(fileName).ToList();
if (ValidateHeader(fileEngine.HeaderText))
{
fileError.ErrorType = ImportFileFaultType.InvalidHeaderRecordType;
fileError.ErrorMessage = "No header record in the file.";
}
else
{
PopulateErrors(fileError, fileEngine.ErrorManager);
}
return records;
}
private FileHelperEngine<T> InitializeFileEngine<T>(Func<EngineBase, AfterReadEventArgs<T>> afterReadFunc) where T : class
{
var fileEngine = new FileHelperEngine<T>(Encoding.Default);
fileEngine.ErrorMode = ErrorMode.SaveAndContinue;
if (afterReadFunc != null)
{
fileEngine.AfterReadRecord += afterReadFunc;
}
return fileEngine;
}
private void PopulateErrors(ImportFileError fileError, ErrorManager errorManager)
{
if (errorManager.Errors.Count() > 0)
{
fileError.ErrorType = ImportFileFaultType.InvalidDetailRecordType;
fileError.ErrorData = new List<string>();
}
foreach (var error in errorManager.Errors)
{
string errorString = string.Format("Line:{0} Field:{1} - ErrorInfo:{2}",
error.LineNumber,
((ConvertException)error.ExceptionInfo).FieldName,
error.ExceptionInfo.InnerException);
fileError.ErrorData.Add(errorString);
}
}
private bool ValidateHeader(string headerRecord)
{
bool isheaderValid;
if (!string.IsNullOrEmpty(headerRecord) &&
!string.IsNullOrEmpty(headerRecord.Trim(new char[] { '\r', '\n' })))
{
isheaderValid = true;
}
else
{
isheaderValid = false;
}
return isheaderValid;
}
}
I am getting the non- assignable error at fileEngine.AfterReadRecord += afterReadFunc;
Can Someone help.
I've cut your code down slightly, but the issue is that an AfterReadHandler<T> isn't an Func<EngineBase, AfterReadEventArgs<T>> (nor is it a Action<EngineBase, AfterReadEventArgs<T>>.
You have two choices to fix your code.
(1)
private FileHelperUtility<T> InitializeFileEngine<T>(AfterReadHandler<T> afterReadFunc) where T : class
{
var fileEngine = new FileHelperUtility<T>();
if (afterReadFunc != null)
{
fileEngine.AfterReadRecord += afterReadFunc;
}
return fileEngine;
}
(2)
private FileHelperUtility<T> InitializeFileEngine<T>(Action<EngineBase, AfterReadEventArgs<T>> afterReadFunc) where T : class
{
var fileEngine = new FileHelperUtility<T>();
if (afterReadFunc != null)
{
fileEngine.AfterReadRecord += (eb, area) => afterReadFunc(eb, area);
}
return fileEngine;
}
Let me know if this isn't clear enough.
As I understand that you're using Func<T, TResult> Delegate the second param is TResult it's not the same with AfterReadHandler delegate.
Can you try to use Action<T1, T2> Delegate instead.
Refs here:
Func in msdn,
Action in msdn
I am in the process of converting code from VB to C# from an old system that used a base classes for web forms to inherit classes from. My hope is to build a new login for our new extranet that functions like the old system, I may have missed a step but here is the block I tried to convert.
public bool CheckAD()
{
string fncADStatus = "Failure";
string fncSuccess = "Success";
string fncFailure = "Failure";
fncADStatus = Convert.ToString(Session["SessionADStatus"]);
try
{
if (fncADStatus == fncSuccess)
{
return true;
}
}
catch
{
if (fncADStatus == fncFailure)
{
return false;
}
if (Session["SessionADStatus"] == null)
{
return false;
}
}
}
And I get the following error "not all code path return a value" but I don't quite understand why.
it give you the error because you have not mentioned the else statment; nothing will be returned if condition fall in else. do the following will not give you the errro.
public bool CheckAD() {
string fncADStatus = "Failure";
string fncSuccess = "Success";
string fncFailure = "Failure";
fncADStatus = Convert.ToString(Session["SessionADStatus"]);
try
{
Boolean output = false;
if (fncADStatus == fncSuccess)
{
output = true;
}
return output;
}
catch
{
Boolean output = true;
if (fncADStatus == fncFailure)
{
output = false;
}
if (Session["SessionADStatus"] == null)
{
output = false;
}
return output;
}
}
Not all the code paths in the catch block return a result. Usually, you would write something like this
public bool CheckAD()
{
try {...}
catch
{
if (fncADStatus == fncFailure)
{
logger.Debug("One");
}
if (Session["SessionADStatus"] == null)
{
logger.Debug("Two");
}
return false; // <<<<< This bit is missing in your case
}
}
I am trying to modify an object after its creation. I would like to set the properties of this object to -1 for int or string.empty "" for a string. Bellow is a sample code of what I already have.
class TestClassAccess{
public int MyPropInt { get; set { ModifyOnAccessDenied<int>(value); } }
public string MyPropString { get; set { ModifyOnAccessDenied<string>(value); } }
public TestClassAccess() { }
private T ModifyOnAccessDenied<T>(T propertyToChange) {
var _hasAccess = false; //not really important how this is made
if (!_hasAccess)
{
if (propertyToChange is string)
propertyToChange = string.Empty;
else if (propertyToChange is int)
propertyToChange = -1;
}
return propertyToChange;
}
}
so.. issues i am having.
It doesn't compile as I cannot convert property to change to string or int.
I don't knot if i can use set methods like this.
Is this possible or am i being to ambitious.
Thank.s
KJ
If you are checking for specific types in a generic function you are probably doing something wrong. In this case you can easily just pass in a default value rather than having it hard coded:
private T ModifyOnAccessDenied<T>(T newValue, T defaultValue) {
var _hasAccess = false; //not really important how this is made
if (!_hasAccess)
{
newValue = defaultValue;
}
return newValue;
}
I've also renamed propertyToChange to newValue because what you have in this function is the new value, not a property.
Also your property definitions will not work. If you need to include any logic in your getter or setting you cannot use the auto-initializer syntax and must implement the property with a backing field.
There doesn't seem to be a point in making this function generic if it needs specific action for each type. This seems more appropriate.
class TestClassAccess
{
public int MyPropInt { get; set { ModifyOnAccessDenied<int>(value); } }
public string MyPropString { get; set { ModifyOnAccessDenied<string>(value); } }
public TestClassAccess() { }
private static volatile bool _hasAccess = false;
private string ModifyOnAccessDenied<string>(string propertyToChange)
{
if (!_hasAccess)
return string.Empty;
return propertyToChange;
}
private int ModifyOnAccessDenied<int>(int propertyToChange)
{
if (!_hasAccess)
return -1;
return propertyToChange;
}
}
You can however do this using dynamics, but this does require .NET 4.0
private T ModifyOnAccessDenied<T>(T propertyToChange)
{
if (!_hasAccess)
{
if (propertyToChange is string)
return (dynamic)string.Empty;
else if (propertyToChange is int)
return (dynamic)(int)-1;
}
return propertyToChange;
}
Fully working sample:
static class Program
{
[STAThread]
static void Main()
{
TestClassAccess test = new TestClassAccess();
test.MyPropInt = 4;
test.MyPropString = "TEST";
Console.WriteLine("MyPropInt {0}, MyPropString '{1}'",test.MyPropInt, test.MyPropString);
// Prints "MyPropInt -1, MyPropString ''
}
class TestClassAccess
{
private int myPropInt = 0;
public int MyPropInt { get { return myPropInt; } set { myPropInt = ModifyOnAccessDenied<int>(value); } }
private string myPropString = string.Empty;
public string MyPropString { get { return myPropString; } set { myPropString = ModifyOnAccessDenied<string>(value); } }
public static volatile bool _hasAccess = false;
private T ModifyOnAccessDenied<T>(T propertyToChange)
{
if (!_hasAccess)
{
if (propertyToChange is string)
return (dynamic)string.Empty;
else if (propertyToChange is int)
return (dynamic)(int)-1;
}
return propertyToChange;
}
}
}
have a php code like this,going to convert it in to C#.
function isValid($n){
if (preg_match("/\d+/",$n) > 0 && $n<1000) {
return true;
}
return false;
}
Here is my try,BUT error shown Error is "expected class, delegate, enum, interface or struct error C#"
public string IsValidate(string Item)
{
string Result = Item;
try
{
Result = System.Text.RegularExpressions.Regex.Replace(InputTxt, #"(\\)([\000\010\011\012\015\032\042\047\134\140])", "$2");
}
catch(Exception ex)
{
console.WriteLine(ex.Message)
}
return Result;
}
What is the error,Is there any other way to implement this better than my try ?
i got this snippet from here code
You haven't define this method inside a class/struct that is why you are getting this error. You may define this method inside a class.
public class MyValidator
{
public string IsValidate(string Item)
{
//Your code here
}
}
Later you can use it like:
MyValidator validator = new MyValidator();
validator.IsValid("Your string");
Also you are missing semicolon at the end of the Console.Write statement, plus 'c' for Console should be in uppercase
Edit:
Since in your php code, it looks like you are trying to see if the string passed is an integer and it is less than 1000, you may use the int.TryParse like the following:
public class MyValidator
{
public bool IsValidate(string Item)
{
string Result = Item;
int val;
if (int.TryParse(Item, out val) && val > 0 && val < 1000)
{
return true;
}
else
{
return false;
}
}
}
In you main method you can do:
static void Main()
{
MyValidator validator = new MyValidator();
Console.WriteLine(validator.IsValidate("asdf123")); // This will print false
Console.WriteLine(validator.IsValidate("999")); //This will print true
Console.WriteLine(validator.IsValidate("1001")); //This will print false
}
In C# a method must be placed inside a class or struct:
public class Validator {
public string IsValidate(string item) {
...
}
}
In this case I would probably translate it like this:
public static class Validator {
public static bool IsValid(string item) {
int value;
return int.TryParse(item, out value)
&& value > 0 && value < 1000;
}
}
You could define your function inside a static class such that you dont have to create an instance of it before invoking the function. Like,
public static class Validator
{
public static string IsValidate(string item)
{
// ...
}
}
Then, you can call it using:
Validator.IsValidate("String to validate")
EDIT: You could then check that your function is returning what you expect by doing:
if(Validator.IsValidate("String to validate") == "Expected result")
{
/* Logic to be executed here */
}