return a value depending on condition - c#

Assuming I have the following extension method:
public static string sampleMethod(this int num) {
return "Valid";
}
how can I terminate sampleMethod and show a messagebox if num > 25 ?
If I try below code,I receive a red underline on the sampleMethod and says not all code path returns a value.
public static string sampleMethod(this int num) {
if(num > 25) {
MessageBox.Show("Integer must not exceed 25 !");
} else {
return "Valid String";
}
}
and if I add throw new Exception("..."); under the MessageBox.Show, everything goes well but the application terminates.
how can I show the MessageBox and terminate the Method instead if the condition is not met ?
Thank you.

Make sure you always return a string (since string is your return value) to all possible outcome/path of your function
public static string sampleMethod(this int num) {
if(num > 25) {
MessageBox.Show("Integer must not exceed 25 !");
return "";
}
return "Valid String";
}
your code didn't work because
public static string sampleMethod(this int num) {
if(num > 25) {
MessageBox.Show("Integer must not exceed 25 !");
// when it go to this block, it is not returning anything
} else {
return "Valid String";
}
}

Suppose you have array of strings with 25 indexes:
public String[] data = new String[25] { /* declare strings here, e.g. "Lorem Ipsum" */ }
// indexer
public String this [int num]
{
get
{
return data[num];
}
set
{
data[num] = value;
}
}
The method should be changed as below if you not want to return any string when the array index exceeds 25:
public static String sampleMethod(this int num) {
if(num > 25) {
MessageBox.Show("Integer must not exceed 25 !");
return String.Empty; // this won't provide any string value
} else {
return "Valid String";
}
}

Related

Wrong value displayed

I'm learning C#, I have this code :
namespace foo
{
public class Personnes
{
string[] m_Noms;
int m_NbElt;
int m_Max;
public Personnes(int Max)
{
m_Max = Max;
m_NbElt = 0;
m_Noms = new string[Max];
}
public int this[string Nom]
{
get { return Array.IndexOf(m_Noms, Nom); }
}
public string this[int i]
{
get { return m_Noms[i]; }
set { m_Noms[i] = value;m_NbElt++; }
}
}
class Prog
{
static void Main(string[] args)
{
Personnes Tableau = new Personnes(4);
Tableau[0] = "Anna";
Tableau[1] = "Ingrid";
Tableau[2] = "Maria";
Tableau[3] = "Ulrika";
Console.WriteLine(Tableau[1]);
Console.WriteLine(Tableau["Maria"]);
Console.WriteLine(Tableau[10]);
Console.WriteLine(Tableau["Toto"]);
}
}
}
I've been told that Console.WriteLine(Tableau[10]); should display null and the next line -1 but it doesn't, instead I have an error IndexOutOfRange, why ?
It is displaying IndexOutOfRangeException because you have set Tableau to have only 4 strings and any array retrieval beyond the index range[0 to 3] will result in this.
public string this[int i]
{
get { return m_Noms[i]; } <-- displays error if outside the range
set { m_Noms[i] = value;m_NbElt++; }
}
If you have to display null, then you need to add conditions in the indexer logic to check for the index value and if it is out of range return null
See you have initialized your array Tableau with just 4 Personnes(4). And you are trying to get what is at Tableau[10], so your are correctly getting IndexOutOfRange exception. The index that you are seeking is out of the range specified.
I've been told that Console.WriteLine(Tableau[10]); should display null and the next line -1 but it doesn't, instead I have an error IndexOutOfRange, why ?
Because whoever told you that was wrong. Accessing an array with an index that does not exist should throw an exception.

Simple Unit Testing - Parse Invalid Input To Throw Error C# Visual Studio

I have a very basic method that divides two double values.
For unit testing I want to include a invalid input (string) to throw error message or exception. What is most simple way to parse the value or fail the test (expected)?
CalculatorClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Calculator
{
public class CalculatorClass
{
//METHODS
public double Divide(double num1, double num2)
{
double result = num1 / num2;
return result;
}
}
}
UnitTest1.cs
using System;
using Calculator; //ADD REFERENCE
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace CalcMethodTest
{
//AreEqual
//AreNotEqual
//AreNotSame
//AreSame
//Equals
//Fail
//Inconclusive
//IsFalse
//IsInstanceOfType
//IsNotNull
//IsNull
//IsTrue
//ReplaceNullChars
[TestClass]
public class UnitTest1
{
[TestMethod]
public void _1_3_Test_Divide_Input_Seven_2_Output_Error()
{
//ARRANGE
CalculatorClass calcObj = new CalculatorClass();
string expectedOutput = "Error - Invalid Input";
//ACT
//----HERE WRONG DATA TYPE FOR TESTING----
double result = calcObj.Divide("Seven", 2);
//ASSERT
Assert.AreEqual(expectedOutput, result);
}
}
}
Since your Divide method takes input of double,double the string wrong data type you use cannot be used as input.
In order to allow the input to be string or number, I suggest you to change the argument type to a base class common to both (say, object) and then expand the Divide by trying to parse the data - returning false if the process cannot be finished (or if the exception occur, up to you), similar to TryParse method provided by .Net. You can also extend the out variable to include the error string if you find it suitable.
Also, more appropriate name would be TryDivide than Divide:
namespace Calculator {
public class CalculatorClass {
//METHODS
public bool TryDivide(object num1, object num2, out double doubleVal, out string errorString) {
doubleVal = 0;
errorString = string.Empty;
try {
if (num1 == null || num2 == null) {
errorString = "number(s) cannot be null";
return false;
}
double num = 0, den = 0;
bool parseResult;
if (num1 is double)
num = (double)num1;
else {
parseResult = double.TryParse(num1.ToString(), out num);
if (!parseResult) {
errorString = "numerator cannot be parsed as double";
return false;
}
}
if (num2 is double)
den = (double)num2;
else {
parseResult = double.TryParse(num2.ToString(), out den);
if (!parseResult) {
errorString = "denominator cannot be parsed as double";
return false;
}
}
doubleVal = num / den;
return true;
} catch (Exception ex) {
errorString = ex.ToString();
return false; //may also be changed to throw
}
}
}
}
Just then you will be able call your TryDivide with string input:
double doubleResult;
string errorString;
bool result = calcObj.TryDivide("Seven", 2, out doubleResult, out errorString);
if (!result){ //something is wrong
Console.WriteLine(errorString);
}
You are not able to pass a string where a double parameter is expected. If you absolutely need to be able to pass a string parameter to this method, you should not expect it to fail based on it being an invalid type - only if the conversion to a double failed. In that case, I'd attempt some rudimentary parsing of a string to a double (however in that case you'd probably only want to parse "7", not "seven" - up to you though).
What you have written will never be able to get tested, purely because it will never compile using C#.
If all you want is to test exception handling in unit tests and how you can fail tests by passing wrong arguments, look at this example.
public class Sum
{
//Returns the sum of 2 positive odd integers
//If either of arguments is even, return -1
//If either of arguments is negative, throw exception
public int PositiveSumOddOnly(int a, int b)
{
if(a < 0 || b < 0)
throw new InvalidArgumentException("One or more of your arguments is negative");
if(a%2 == 0 || b%2 == 0)
return -1;
return a + b;
}
}
[TestClass]
public class Sum_Test
{
[TestMethod]
public int PositiveSumOddOnly_ShouldThrowInvalidArgumentExecption(int a, int b)
{
Sum s = new Sum();
try
{
int r = s.PositivesumOddOnly(1,-1);
}
catch(InvalidArgumentException e)
{
Assert.AreEqual("One or more of your arguments is negative", e.Message);
}
}
[TestMethod]
public int PositiveSumOddOnly_ShouldReturnNegativeOne(int a, int b)
{
Sum s = new Sum();
int r = s.PositiveSumOddOnly(1,2);
Assert.AreEqual(r,-1);
}
[TestMethod]
public int PositiveSumOddOnly_ShouldReturnSumOfAandB(int a, int b)
{
Sum s = new Sum();
int r = s.PositiveSumOddOnly(1,1);
Assert.AreEqual(r,2);
}
}
This seems to work:
[TestMethod]
public void _1_3_Test_Divide_Input_Seven_2_Output_Error()
{
//ARRANGE
CalculatorClass calcObj = new CalculatorClass();
string expectedOutput = "Error - Invalid Input";
//ACT
//----CHANGED TO STRING. THEN CAST BACK TO DOUBLE INSIDE METHOD----
string result = calcObj.Divide("Seven", "2");
//ASSERT
Assert.AreEqual(expectedOutput, result);
}
Method:
public string Divide(string num1, string num2)
{
string resultMsg = "";
try
{
double num1Dbl = double.Parse(num1);
double num2Dbl = double.Parse(num2);
double result = num1Dbl / num2Dbl;
resultMsg = result.ToString();
return resultMsg;
}
catch (FormatException error)
{
resultMsg = "Error - Invalid Input";
return resultMsg;
}
}

How to enforce the maximum and minimum number of characters allowed in a string

I want to limit my string, so that you have to put a minimum of 3 chars and a max of 10 chars in. Is this possible in the following code below?
main.cs:
class Program
{
static void Main(string[] args)
{
Something hello = new Something();
string myname;
Something test = new Something();
myname = Console.ReadLine();
test.Name = myname;
}
}
class with properties:
class Okay : IYes
{
private string thename;
public string Name
{
get {return thename;}
set {thename = value;} //what to put here???
}
}
The setter is probably not the best place to check. You should make the check at the point of input:
string myname = "";
while (myname.Length<3 || myname.Length >10)
{
Console.WriteLine("Please enter your name (between 3 and 10 characters");
myname = Console.ReadLine();
}
test.Name = myname;
Obviously you can take some steps to make this more user friendly: maybe a different message after the first failure, some way of getting out of the loop, etc.
Try this:-
public string Naam
{
get { return thename; }
set
{
if (value.Length >= 3 && value.Length <= 10)
thename = value;
else
throw new ArgumentOutOfRangeException();
}
}
class Okay : IYes
{
private string name;
public string Name
{
get { return name; }
set
{
if (value == null) throw new ArgumentNullException("Name");
if (value.Length < 3 || value.Length > 10)
throw new ArgumentOutOfRangeException("Name");
name = value;
}
}
}
You can also truncate the string if it's too long, rather than throwing an exception by just taking (up to) the first 10 characters:
class Okay : IYes
{
private string name;
public string Name
{
get { return name; }
set
{
if (value == null) throw new ArgumentNullException("Name");
if (value.Length < 3) throw new ArgumentOutOfRangeException("Name");
name = string.Join("", value.Take(10));
}
}
}
private static void GenericTester()
{
Okay ok = new Okay {Name = "thisIsLongerThan10Characters"};
Console.WriteLine(ok.Name);
}
// Output:
// thisIsLong

depending on var count build string

I have List<string> num. Depending on count of num, I need to build a string like:
if num consists of 561924630638
{"formType":"Status", "postDataList":[{"textWithMentions":{"text":"gogogo"}},{"imageData":{"imageIds":["561924630638"], "typeAndSizes":["561924630638,0,300,290"]}}], "news":false, "toStatus":true}
if num consists of 561924630638 and 561924630894
{"formType":"Status", "postDataList":[{"textWithMentions":{"text":"gogogo"}},{"imageData":{"imageIds":["561924630638","561924630894"], "typeAndSizes":["561924630638,0,300,290","561924630894,0,300,290"]}}], "news":false, "toStatus":true}
List<string> _num;
List<string> num
{
get
{
return _num;
}
set
{
_num = value;
// Check the value here and do what you need
if (_num.Contains("561924630638"))
{ }
else if (_num.Contains("561924630638") && _num.Contains("561924630894"))
{ }
}
}

Elegant way to validate values

I have a class with many fields which represents different physical values.
class Tunnel
{
private double _length;
private double _crossSectionArea;
private double _airDensity;
//...
Each field is exposed using read/write property. I need to check on setter that the value is correct and generate exception otherwise. All validations are similar:
public double Length
{
get { return _length; }
set
{
if (value <= 0) throw new ArgumentOutOfRangeException("value",
"Length must be positive value.");
_length = value;
}
}
public double CrossSectionArea
{
get { return _crossSectionArea; }
set
{
if (value <= 0) throw new ArgumentOutOfRangeException("value",
"Cross-section area must be positive value.");
_crossSectionArea = value;
}
}
public double AirDensity
{
get { return _airDensity; }
set
{
if (value < 0) throw new ArgumentOutOfRangeException("value",
"Air density can't be negative value.");
_airDensity = value;
}
}
//...
Is there any elegant and flexible way to accomplish such validation?
Assuming you want this sort of behaviour, you might consider some helper methods, e.g.
public static double ValidatePositive(double input, string name)
{
if (input <= 0)
{
throw new ArgumentOutOfRangeException(name + " must be positive");
}
return input;
}
public static double ValidateNonNegative(double input, string name)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(name + " must not be negative");
}
return input;
}
Then you can write:
public double AirDensity
{
get { return _airDensity; }
set
{
_airDensity = ValidationHelpers.ValidateNonNegative(value,
"Air density");
}
}
If you need this for various types, you could even make it generic:
public static T ValidateNonNegative(T input, string name)
where T : IComparable<T>
{
if (input.CompareTo(default(T)) < 0)
{
throw new ArgumentOutOfRangeException(name + " must not be negative");
}
return input;
}
Note that none of this is terribly i18n-friendly...
All depends what technology you are using - if you're under MVC you can use Attributes, like this;
http://msdn.microsoft.com/en-us/library/ee256141(v=vs.98).aspx
Here's my version, it's a bit cleaner than Jon's version in some respects:
interface IValidator <T>
{
bool Validate (T value);
}
class IntValidator : IValidator <int>
{
public bool Validate (int value)
{
return value > 10 && value < 15;
}
}
class Int2Validator : IValidator<int>
{
public bool Validate (int value)
{
return value > 100 && value < 150;
}
}
struct Property<T, P> where P : IValidator<T>, new ()
{
public T Value
{
set
{
if (m_validator.Validate (value))
{
m_value = value;
}
else
{
Console.WriteLine ("Error validating: '" + value + "' is out of range.");
}
}
get { return m_value; }
}
T m_value;
static IValidator<T> m_validator=new P();
}
class Program
{
static void Main (string [] args)
{
Program
p = new Program ();
p.m_p1.Value = 9;
p.m_p1.Value = 12;
p.m_p1.Value = 25;
p.m_p2.Value = 90;
p.m_p2.Value = 120;
p.m_p2.Value = 250;
}
Property<int, IntValidator>
m_p1;
Property<int, Int2Validator>
m_p2;
}
Try to use such a method:
public void FailOrProceed(Func<bool> validationFunction, Action proceedFunction, string errorMessage)
{
// !!! check for nulls, etc
if (!validationFunction())
{
throw new ArgumentOutOfRangeException(errorMessage);
}
proceedFunction();
}
Yes, by creating your own validation attributes.
Read this article: Business Object Validation Using Attributes in C#
I will have the decency of NOT copying it here :)
Using the Validator function I mentioned in my comment above, I'd do something like this (untested code):
void textBox_Changed(object sender, EventArgs e) {
submitButton.Enabled = validator();
}
bool validator() {
const string NON_POSITIVE = "Value must be greater than Zero";
bool result = false;
string controlName = "Length";
try {
_length = Convert.ToDouble(txtLength.Text);
if (_length <= 0) throw new Exception(NON_POSITIVE);
controlName = "Cross Section Area";
_crossSectionArea = Convert.ToDouble(txtCrossSectionArea.Text);
if (_crossSectionArea <= 0) throw new Exception(NON_POSITIVE);
controlName = "Air Density";
_airDensity = Convert.ToDouble(txtAirDensity.Text);
if (_airDensity <= 0) throw new Exception(NON_POSITIVE);
result = true; // only do this step last
} catch (Exception err) {
MessageBox.Show(controlName + " Error: " + err.Message, "Input Error");
}
return result;
}
John Skeet probably has a better way, but this works. :)
You can achieve this using classes from System.ComponentModel.DataAnnotations
class Tunnel
{
[Range(0, double.MaxValue, ErrorMessage = "Length must be positive value.")]
public double Length { get; set; }
}
Validation:
var tunnel = new Tunnel { Length = 0 };
var context = new ValidationContext(tunnel, null, null);
Validator.ValidateObject(tunnel, context, true);
Also you can implement your own validation attributes overriding ValidationAttribute class

Categories