I have been writing a check in a name property of my person abstract class. The problem that i have is that i am trying to implement a piece of code that will not allow the user to leave the field empty or to exceed the name limit with 35characters or in-put a digit but i am stuck with it. If any one can help or suggest me.
public string Name
{
get { return name; }
set
{
while (true)
{
if (value == "" || value.Length > 35)
{
Console.Write("Please Enter Correct Name: ");
value = Console.ReadLine();
continue;
}
foreach (char item in value)
{
if (char.IsDigit(item))
{
Console.Write("Digits Are NotAllowed....\n");
Console.Write("Please Enter Correct Name: ");
value = Console.ReadLine();
break;
}
}
break;
}
name = value;
}
}
Don't do any form of UI or I/O in a property.
public string Name
{
get { return _name; }
set
{
if (! Regex.IsMatch(value, #"\w{1-35}"))
throw new ArgumentException("Name must be 1-35 alfanum");
_name = value;
}
}
The exact regular expression is up for discussion but the best practice:
do not try to list and reject all the patterns you don't like. Too much possibilities.
accept what you expect (and understand), reject everything else.
This sort of validation should be broken up. The setter should only know the various restrictions that it has and throw an exception in the case that an invalid value makes it that far. Do not put user interface code in there.
Try something like this:
public string Name
{
get { return name; }
set
{
if (value == "" || value.Length > 35)
{
throw new ArgumentException("Invalid name length.");
}
foreach (char item in value)
{
if (char.IsDigit(item))
{
throw new ArgumentException("Digits are not allowed.");
}
}
name = value;
}
}
Then something like this in your console application:
bool success = false;
while(!success)
{
try
{
Console.WriteLine("Please enter a name:");
myObject.Name = Console.ReadLine();
success = true;
}
catch(ArgumentException ex)
{
Console.WriteLine(ex.Message);
}
}
First of all, never ask for Console input inside of a setter. It is a seriously bad practice. Instead, you should throw an Exception from the setter and let the caller handle that however they need:
public string Name
{
get { return name; }
set
{
if(String.IsNullOrWhiteSpace(value))
throw new ArgumentException("Name must have a value");
if(value.Length > 35)
throw new ArgumentException("Name cannot be longer than 35 characters");
if(value.Any(c => char.IsDigit(c))
throw new ArgumentException("Name cannot contain numbers");
name = value;
}
}
You can then catch and handle the Exceptions appropriately in the calling code (which, in your case, would involve re-prompting the user for the input).
The solution for handling this according to your rules are almost obvious but the thing is, it's better not to put the checking and validating logic in the setter method of a property, you can have a separate class for instance and that class does the validation responsibility for you and you can tell it to do that and then use the result appropriately. In that case you are following "Tell, Don't Ask" rule and also "Single Responsibility Principle"
Good Luck
public string Name
{
get { return name; }
set { name = value; }
}
public static bool IsNameValid(string name)
{
if (string.IsNullOrEmpty(name) || name.Length > 35)
{
return false;
}
foreach (char item in value)
{
if (!char.IsLetter(item))
{
return false;
}
}
return true;
}
Finally a code snippet for reading an user input.
var yourClassInstance = new YourClass();
string input
bool inputRead = false;
while(!inputRead)
{
var input = Console.ReadLine();
inputRead = YourClass.IsNameValid(input);
}
yourClassInstance.Name = inputRead;
The short answer for this is to loop while the value is not valid:
public string GetName()
{
String name = String.Null;
do
{
Console.Write("Please Enter Correct Name: ");
name = Console.ReadLine();
} while (!ValidateName(name))
}
public bool ValidateName(string name)
{
//String validation routine
}
That being said, as I'm sure you will see from other answers, change where the Name is given. As a general rule, accessors are really just for "getting" and "setting" quickly what's in a class.
I would create a method for changing the name that contains the validation logic. If you want to check the name is valid, so you don't have to handle the argumentexception do a check first, call IsValidName before calling ChangeName
public class Person
{
public void ChangeName(string name)
{
if (!IsValidName(name))
{
throw new ArgumentException(....);
}
else
this.Name = value;
}
public bool IsValidName(string name)
{
// is the name valid using
}
public string Name { get; private set; }
}
And to use it
var newName = Console.ReadLine();
var person = new Person();
while (!person.IsValidName(newName))
{
newName = Console.ReadLine();
}
person.ChangeName(newName);
From a semantics point of view, a setter is as its name says, a setter! It should be used to set a private/protected field of a class
From a testability point of view, your design is very hard to be automatically tested not to say impossible!
This reminds me of a bit of code I worked on sometime ago where a setter is opening a socket and sending stuff over the network!
The code should do what it reads, just imagine if someone uses your code, calls your setter and wonders why on earth does his/her application hang (waiting for user input)
The way I see your code more readable and testable is to have a verifer class that ensures the user is entering the right data in the right format. The verifier should take an input stream as data source, this will help you easily test it.
Regards,
Aside from what Mr Skeet said, seems like you should replace this break with a continue in order to validate the new value (like you do in your first length check):
if (char.IsDigit(item))
{
Console.Write("Digits Are NotAllowed....\n");
Console.Write("Please Enter Correct Name: ");
value = Console.ReadLine();
continue; //here
}
Related
I'm relatively new/inexperienced to c# and I am trying to write a bool method to validate if the user input in a windows form is empty, which returns as true or false, as well as change the errorMessage Variable to have new text if it returns false.
public static bool IsPresent(string value)
{
if (value == "")
{
errorMessage = "all textboxes and combo boxes must be filled";
return false;
}
else
{
errorMessage = "";
return true;
}
}
I get compile time error on errorMessage, saying
"An object reference is required for the nonstatic field, method, or property 'member'".
I declared the errorMessage variable at the top of my file and made it public.
I have tried getting rid of the static aspect of the method, which does fix it, but causes more errors elsewhere in my code.
Do you know how I can go about fixing this?
You can declare public static field and do it like this of course:
static class Helper
{
public static string errorMessage;
public static bool IsPresent(string value)
{
if (value == "")
{
errorMessage = "all textboxes and combo boxes must be filled";
return false;
}
else
{
errorMessage = "";
return true;
}
}
}
But this's got a few problems, one of them is that errorMessage can be now modified by some foreign class, so it should be changed to something else, for example:
private static string errorMessage;
public static string GetMessageCopy()
{
return errorMessage;
}
You can change this to property, which does the same thing, but it's easier to read:
public static string ErrorMessage { get; private set; } // property should always start with a big letter
Now only Helper class can modify ErrorMessage, but everyone can read it.
Next problem is that name of your parameter "value" is a C# keyword, which is used for different things, so please, think of renaming it.
You need to declare variable first inside the static function. If you have declared it outside the method's scope I recommend removing the static keyword so it should look like this:
string errorMessage;
bool IsPresent(string value)
{
if (value == "")
{
errorMessage = "all textboxes and combo boxes must be filled";
return false;
}
else
{
errorMessage = "all textboxes and combo boxes must be filled";
return true;
}
}
You should read up on static. You could start with static (C# Reference).
However, there are solutions that don't require a member variable (what you called at the top of my file) and avoid the static/non-static issue. For example, let's consider this solution:
(bool IsValid, string? ErrorMessage) IsPresent(string? s)
{
if (string.IsNullOrEmpty(s))
{
return(IsValid: false, ErrorMessage: "All textboxes and combo boxes must be filled");
}
else
{
return(IsValid: true, ErrorMessage: null);
}
}
Notes:
Please note I used string.IsNullOrEmpty rather than == "". You may want to use string.IsNullOrWhiteSpace to make the requirement even stronger.
You may need to change (bool IsValid, string? ErrorMessage) IsPresent(string? s) to (bool IsValid, string ErrorMessage) IsPresent(string s) if you're not using a fresh version of .NET.
If we think about it a bit more we can notice that IsValid is redundant. Checking if the error is return is enough:
string? CheckValid(string? s)
{
if (string.IsNullOrWhiteSpace(s))
{
return "All textboxes and combo boxes must be filled";
}
//if ( ... some other requirement )
//{
// return "Some error";
//}
return null;
}
I am new to C# and was wondering what I am doing wrong while working with get and set.
I have a VendingMachine that, when I input a number for the beverage that I want, it subtracts from the total.
private int _coke = 2;
public int Beer = 20;
public int LemonLime = 20;
public int Grape = 20;
public int CreamSoda = 20;
public bool AnohterBevrage;
The problem is that it keeps subtracting even after it reaches 0. Well, there cant be -1 Coke left in the Machine. So, I tried this.
public int Coke
{
get => _coke;
set
{
if (_coke == 0)
{
_coke = value;
Console.WriteLine("No more Coke Left!");
}
}
}
But it doesn't work, so I'm not sure where I'm getting stuck. I'm not sure if the Math function is relevant here.
If there is something missing, let me know. I will try and adjust. This getter and setter gets me all confused.
EDIT: Add function
public void Math()
{
var input = Console.ReadKey();
while (input.Key == ConsoleKey.D1)
{
do
{
_coke--;
Console.WriteLine("\nTotal Coke Left: " + Coke);
Console.Write("\nWould You like Another Bevrage ?y/n: ");
if (Console.ReadLine() == "y")
{
AnohterBevrage = true;
Content();
Math();
}
else
{
AnohterBevrage = false;
}
break;
} while (AnohterBevrage == true);
}
}
if (_coke == 0)
You're checking the current value.
That means that you can only set the property if it is currently 0.
When you start trying to do something, you need to build a model of what you are doing. Using getters/setters as your UI is not a great design (as #Rufus L pointed out). Instead, picture a Coke machine in your head. There are racks of various drinks (that get restocked), and then a mechanical system that implements a user interface that allows someone to pick a drink and get it delivered. You should separate your design into those two parts.
One hint that your design needs work is that your main function (that's doing all the work) is named "Math". If you were to look at this code in two months, you'd see "Math" and not have a clue it represented a Coke machine.
I wrote a quickie coke machine that matches your needs (well, I think it does). It uses that same mental model, a set of beverage racks and a controller. I did this with a simple class that represents a rack of drinks and a controller written in a console app's main routine (so everything is static).
The RackOfBeverage class (it includes a restock method that's never called):
class RackOfBeverages
{
public string Label { get; }
public int Count { get; private set; }
public RackOfBeverages(string label, int initialCount)
{
Label = label;
Count = initialCount;
}
public void Restock(int howMany)
{
Count += howMany;
}
public bool Dispense()
{
if (Count > 0)
{
--Count;
return true;
}
else
{
return false;
}
}
}
It has a label (indicating what kind of drink it is), an inventory/count and a Dispense method. The Dispense call will return false if there are no drinks left.
Then I wrote a simple controller (as the Main method in a console app along with a few other bits that I put in the Program class):
class Program
{
private static readonly Dictionary<string, RackOfBeverages> Beverages =
new Dictionary<string, RackOfBeverages>
{
{"COKE", new RackOfBeverages("Coke", 2)},
{"SPRITE", new RackOfBeverages("Sprite", 20)},
//etc.
};
static void Main(string[] args)
{
Console.WriteLine("Welcome to the machine\r\nType a selection (type \"Exit\" to quit)");
while (true)
{
var selection = Console.ReadLine();
//did the user enter the name of a drink
if (Beverages.Keys.Contains(selection, StringComparer.OrdinalIgnoreCase))
{
var beverage = Beverages[selection.ToUpper()];
//was there enough to dispense a drink
if (beverage.Dispense())
{
Console.WriteLine($"Here's your {beverage.Label}");
}
else
{
Console.WriteLine($"Sorry, no {beverage.Label} for you");
}
}
//or, perhaps, the user chose to exit the app
else if (selection.ToUpper() == "EXIT")
{
Console.WriteLine("Exiting");
break;
}
//finally, if the user didn't enter anything I understand
//let him/her know and then let him/her try again
else
{
Console.WriteLine("Pick a valid selection");
}
}
}
}
Separating out the "concerns" in an application is important. Here, the UI is completely separate from the beverage storage. If you want to add another beverage, just add it to the Dictionary up at the top, and the UI will continue to function with the old beverages and the new beverage you added.
I guess you want this code, If _coke less than 0 show message ,otherwise subtract _coke value.
public int Coke
{
get { return _coke; }
set
{
if (_coke <= 0)
{
Console.WriteLine("No more Coke Left!");
}
else
{
_coke = value;
}
}
}
I have a pipe delimited line in a text file. What is the best way to validate the line. I have a definite format for how each token in the line should be i.e for eg; say 5th item should be a date.
Could anyone help me what is the best object oriented way to achive this?Is there any design pattern to achieve this?
Thanks
You're looking for a specific pattern for validation. That can be done any number of ways, but the simplest is to validate in the constructor of the object. Since you're looking for a more OO approach, you might consider creating an object to represent the file and an object to represent each record. There's no real pattern here other than associational. You could, however, utilize the iterator pattern to allow your records to be iterated in a loop. You're talking about reading a text file so that's not complicated enough of a process, but if it was, you could consider a factory pattern to create the file object. If there's a lot to validate, then you could create a separate method to validate each in your class. Here's an example of what I'm talking about...
static void Main(string[] args)
{
DataFile myFile = new DataFile(#"C:\...");
foreach (DataRecord item in myFile)
{
Console.WriteLine("ID: {0}, Name: {1}, StartDate: {2}", item.ID, item.Name, item.StartDate);
}
Console.ReadLine();
}
public class DataFile : IEnumerable<DataRecord>
{
HashSet<DataRecord> _items = new HashSet<DataRecord>();
public DataFile(string filePath)
{
// read your file and obtain record data here...
//I'm not showing that
//... then begin iterating through your string results
//... though I'm only showing one record for this example
DataRecord record = new DataRecord("1234|11-4-2015|John Doe");
_items.Add(record);
}
public IEnumerator<DataRecord> GetEnumerator()
{
foreach (DataRecord item in _items)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class DataRecord
{
private int _id;
public int ID
{
get { return _id; }
private set { _id = value; }
}
private DateTime _startDate;
public DateTime StartDate
{
get { return _startDate; }
private set { _startDate = value; }
}
private string _name;
public string Name
{
get { return _name; }
private set { _name = value; }
}
internal DataRecord(string delimitedRecord)
{
if (delimitedRecord == null)
throw new ArgumentNullException("delimitedRecord");
string[] items = delimitedRecord.Split('|');
//You could put these in separate methods if there's a lot
int id = 0;
if (!int.TryParse(items[0], out id))
throw new InvalidOperationException("Invalid type...");
this.ID = id;
DateTime startDate = DateTime.MinValue;
if (!DateTime.TryParse(items[1], out startDate))
throw new InvalidOperationException("Invalid type...");
this.StartDate = startDate;
//This one shouldn't need validation since it's already a string and
//will probably be taken as-is
string name = items[2];
if (string.IsNullOrEmpty(name))
throw new InvalidOperationException("Invalid type...");
this.Name = name;
}
}
The "clean" way for achieve this would be to use Regular Expression. Here is a basic example :
var allLines = new List<string>();
for (int i = 0; i < 5; i++)
{
allLines.Add("test" + i);
}
// if you add this line, it will fail because the last line doesn't match the reg ex
allLines.Add("test");
var myRegEx = #"\w*\d"; // <- find the regex that match your lines
Regex regex = new Regex(myRegEx);
var success = allLines.All(line => regex.Match(line).Success);
In this example, my regex is waiting for a word immediately followed by a digit. All you have to do is to find the regex that match your line.
You can also avoid the linq expression by using a more complexe reg ex.
Give us your token so we can help you with.
I am using properties to allow a single string name to be added to the class Details, I want the property to only accept the string if it can be split into two parts.
The two parts would be the firstName and the LastName. However if the resulting split has 1,0 or more than 2 strings in the array then the input should be deemed invalid and I want to throw a error to whatever code called the property in the first place.
Can error handling be done on properties like this?
If not then what of the following is the preferred way to get data into a class whilst checking for correctness:
Use a method inside the class Details to handle error inputs, make that method boolean.
Continue using properties but have the error checking done by the code that calls the property. I don't like this because I want all the error checking code to be self-contained in the Details class.
.
class Details
{
private string firstName, lastName;
public string Name
{
// name
get { return firstName + " " + lastName; }
set
{
string name = value;
string[] nameArray = name.Split(' ');
firstName = nameArray[0];
lastName = nameArray[1];
}
}
}
EDIT: I am mostly interested in what of the three options is concidered best pratice:
Error check inside properties.
Error check outside class in another class, and then just add the verified inputs to Details
Use a boolean method inside Details to verify the inputs.
I would follow an existing validation framework, such as FluentValidation.
Also, in your specific case, I would have a SetName(string fullName) method that does the parsing and populating.
Why not use exception to capture the error condition.
private string firstName, lastName;
public string Name
{
get { return string.Concat(firstName, " ", lastName); }
set
{
string name = value;
if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("Name"); }
var nameParts = name.Trim().Split(' ');
if (nameParts.Length != 2) { throw new ArgumentException("Invalid name value"); }
firstName = nameParts[0];
lastName = nameParts[1];
}
}
Just to add my perspective to what others have said, it seems to me that part of the difficulty stems from the fact that you're using a property setter to do something non-trivial (split a string, validate the results, and then store the results in two fields). Generally, properties, especially read/write properties, should only be concerned with getting and setting a single value (using read-only properties to return a simple computed value is common enough too).
If it were me, I'd have separate properties for the first name and last name, with a third computed property for the full name:
class Details
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return string.Concat(this.FirstName, " ", this.LastName); }
}
}
Then you could add a method to set the full name. A method is more appropriate than a property setter for this task, since it's non-trivial and has more potential for problems:
public void SetFullName(string fullName)
{
string[] nameComponents = fullName.split(' ');
if (nameComponents.Length != 2)
{
throw new ArgumentException("The full name must contain a first and last name.");
}
this.FirstName = nameComponents[0];
this.LastName = nameComponents[1];
}
I also want to give a plug for the Code Contracts package. It may be more complication than you're looking for here, but it's a great way of validating input and output in your applications.
So I wouldn't consider data that doesn't meet business logic an exception and thus wouldn't throw one. What I would do is this:
class Details
{
private string firstName, lastName;
public string Name
{
// name
get { return firstName + " " + lastName; }
set
{
string name = value;
string[] nameArray = name.Split(' ');
if(nameArray.Length == 2)
{
firstName = nameArray[0];
lastName = nameArray[1];
}
else
{
firstName = nameArray[0];
lastName = string.Empty;
}
}
}
public bool IsValid()
{
return !string.IsNullOrEmpty(lastName);
}
}
You can then use the name property and then check to see if the name is valid. If not valid, then you can take the appropriate action.
Another option would be to have the validation done in the method calling Details.Name.
EDIT: want to remove what I think is bad advice but keeping so comments make sense, so just striking them out
EDIT2:
You could also do something like this:
class Details
{
private string firstName, lastName;
public string Name
{
get { return firstName + " " + lastName; }
private set;
}
public bool TryParseName(string name)
{
bool isValid = true;
string[] nameParts = name.split(' ');
if(nameParts.Length == 2)
{
firstName = nameParts[0];
lastName = nameParts[1];
}
else
{
isValid = false;
}
return isValid;
}
}
Where you would do
if(details.TryParseName(name))
{
// is valid name
}
else
{
// handle invalid name
}
I have 46 rows of information, 2 columns each row ("Code Number", "Description"). These codes are returned to the client dependent upon the success or failure of their initial submission request. I do not want to use a database file (csv, sqlite, etc) for the storage/access. The closest type that I can think of for how I want these codes to be shown to the client is the exception class. Correct me if I'm wrong, but from what I can tell enums do not allow strings, though this sort of structure seemed the better option initially based on how it works (e.g. 100 = "missing name in request").
Thinking about it, creating a class might be the best modus operandi. However I would appreciate more experienced advice or direction and input from those who might have been in a similar situation.
Currently this is what I have:
class ReturnCode
{
private int _code;
private string _message;
public ReturnCode(int code)
{
Code = code;
}
public int Code
{
get
{
return _code;
}
set
{
_code = value;
_message = RetrieveMessage(value);
}
}
public string Message { get { return _message; } }
private string RetrieveMessage(int value)
{
string message;
switch (value)
{
case 100:
message = "Request completed successfuly";
break;
case 201:
message = "Missing name in request.";
break;
default:
message = "Unexpected failure, please email for support";
break;
}
return message;
}
}
The best would be both a class and an enumeration. Then you can have more descriptive identifiers than "201".
A structure would also work, but they are harder to implement correctly, so you should stick to a class unless you specifically need a structure for some reason.
You don't need to store a reference to the message in the class, you can get that when needed in the Message property. A switch is implemented using a hash table (if there are five values or more), so the lookup is very fast.
public enum ReturnIdentifier {
Success = 100,
MissingName = 201;
}
public class ReturnCode {
public ReturnIdentifier Code { get; private set; }
public ReturnCode(ReturnIdentifier code) {
Code = code;
}
public string Message {
get {
switch (Code) {
case ReturnIdentifier.Success:
return "Request completed successfuly.";
case ReturnIdentifier.MissingName:
return "Missing name in request.";
default:
return "Unexpected failure, please email for support.";
}
}
}
}
Usage:
ReturnCode code = new ReturnCode(ReturnIdentifier.Success);
If you get an integer code from somewhere, you can still use it as the enumerator values correspond to the codes:
int error = 201;
ReturnCode code = new ReturnCode((ReturnIdentifier)error);
(If the integer code doesn't correspond to any of the identifiers in the enumeration, it's still perfectly valid to do the conversion. When getting the Message value, it will end up in the default case as the value doesn't match any of the other cases.)
I think choosing a class(as you did) is a good decision. You can make the code a little more compact and readable, if you use Dictionary<int, string> for mapping codes to descriptions.
_dict.Add(100, "Description1");
_dict.Add(201, "Description2");
...............................
And RetrieveMessage:
return _dict[value];
How about deriving from Dictionary, or storing the data table in code using a Dictionary field that you can index into?
Maybe a dictionary based approach would look more elegant.
private static Dictionary<int, string> errorCodes =
new Dictionary<int, string>()
{
{100, "Request completed successfuly"},
{200, "Missing name in request."}
};
private string RetrieveMessage(int value)
{
string message;
if (!errorCodes.TryGetValue(value, out message))
message = "Unexpected failure, please email for support";
return message;
}
It will definitely be more slower (since it uses Reflection) but speaking of being compact, I think Enums With Custom Attributes is appropriate for this need. Please continue reading the comments since DescriptionAttribute is mentioned there. Something like;
public enum ErrorMessage
{
[System.ComponentModel.Description("Request completed successfuly")]
Success = 100,
[System.ComponentModel.Description("Missing name in request.")]
MissingName = 201
};
public static string GetDescription(this Enum en)
{
Type type = en.GetType();
System.Reflection.MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute),
false);
if (attrs != null && attrs.Length > 0)
return ((System.ComponentModel.DescriptionAttribute)attrs[0]).Description;
}
return en.ToString();
}
static void Main(string[] args)
{
ErrorMessage message = ErrorMessage.Success;
Console.WriteLine(message.GetDescription());
}