I'm trying to modify the "set" portion, but these changes don't seem to take place at all. Here is the basic code that shows the same results:
class Class1
{
private int num;
public Class1(int number)
{
num = number;
}
public int getNumber
{
get
{
return num;
}
set
{
if (value > 0)
num = value;
else
num = 0;
}
}
}
In here, I want to make any negative value a 0.
class Program
{
static void Main(string[] args)
{
Class1 c1 = new Class1(10);
Class1 c2 = new Class1(-10);
Console.WriteLine(c1.getNumber);
Console.WriteLine(c2.getNumber);
Console.ReadLine();
}
}
The result gives me
10
-10
I've tried using
set
{
num = 100;
}
yet there's still no change in the results. I've tried double checking with the book I'm using, and there's no difference that I can see. I'm using Visual Studio 2012 if it means anything.
Your code is not calling set portion of your property. Because, you are only calling constructor. And in your constructor you are only setting tha value for the backing field variable(num).
Also, by convention, your class members names are not appropriate.
Change it as:
num -> number getNumber -> Number
Try this:
Class1 c1 = new Class1();
c1.Number = -10; // The set accessor is invoked here
int myNumber = c1.Number; // The get accessor is invoked here
If you want to invoke set accessor through your constructor, then change your constructor as:
public Class1(int number)
{
Number = number;
}
Then it will invoke set accessor properly:
Class1 c1 = new Class1(10); // The set accessor will be invoked
And don't forget to change your class implementation as:
class Class1
{
private int number;
public int Number
{
get { return number; }
set
{
if (value > 0)
number = value;
else
number = 0;
}
}
// If you do provide a constructor (any constructor with any signature),
// the parametrless constructor will not be generated
public Class1()
{
}
public Class1(int number)
{
Number = number;
}
}
Read this from msdn for additional information.
Try this:
class Class1
{
private int num;
public Class1(int number)
{
Number = number;
}
public int Number
{
get
{
return num;
}
set
{
if (value > 0)
num = value;
else
num = 0;
}
}
}
You hadn't implented it correctly. Actually a better implmentation would be the following:
class Class1
{
// The backing field has the same name as the Property
// but all letters must be lowercase.
private int number;
public int Number
{
get { return number; }
set
{
if (value > 0)
number = value;
else
number = 0;
}
}
// In the constructor we set the value of the backing fields
// using the corresponding properties.
public Class1(int number)
{
Number = number;
}
}
The each time you want to set the value of number or get it's value you use the corresponding property:
// Set the value 2 to the number
Number = 2;
// Read the value stored in number and assigned to value.
var value = Number;
Related
public class Irritante : Child
{
/*Fields*/
private int ir_numeroBirras;
private double ir_mediaBirras;
/*Properties*/
public int NumeroBirras
{
get { return ir_numeroBirras; }
set { if (value > 0) ir_numeroBirras = value; }
}
public double MediaBirras
{
get { return ir_mediaBirras; }
set { ir_mediaBirras = value; }
}
//Constructor
public Irritante(string nome, int idade, int numBirras, double mediaDasBirras) : base(nome, idade)
{
NumeroBirras = numBirras;
ir_mediaBirras = mediaDasBirras;
}
When i try to use the contructor Irritante with the property NumeroBirras it is ignoring the if(value>0)
This means i can still add a 0 to this field with client code, which i should not be able to, any tips? i cant find it anywhere
The default value of ir_numeroBirras is 0. You can't put a 0 using the property. But if you test using a 0 as parameter value, you are being fooled by the default value.
If you're talking about you shouldn't put a 0 in the parameter of Irritante ctor, that's quite different
public Irritante(string name, int idade, int numBirras, double mediaDasBirras) : base(nome, idade)
{
if(numBirras < 1) throw new ArgumentOutOfRangeException(nameof(numBirras), "Hey, you can't drink 0 beers");
ir_numeroBirras = numBirras;
ir_mediaBirras = mediaDasBirras;
}
I am currently improving my program that I posted on CR but I ran into a problem. I have a property called Total but when I try to set it to a value (0) it remains the same.
This is the property:
public class Player
{
private int total;
public int Total
{
get
{
total = 0;
foreach (int card in hand)
{
total += card;
}
return total;
}
set { this.total = value; }
}
}
And here is how I try to change it:
public class Game
{
private void CompareHands()
{
//This is just for testing
Console.WriteLine($"player total: {player1.Total}, is bust: {player1.Bust}");
Console.WriteLine($"house total: {house.Total}, is bust: {house.Bust}");
if (player1.Bust)
player1.Total = 0;
if (house.Bust)
house.Total = 0;
//this too
Console.WriteLine($"player total: {player1.Total}, is bust: {player1.Bust}");
Console.WriteLine($"house total: {house.Total}, is bust: {house.Bust}");
...
}
Also the Bust property if needed:
private readonly int blackjack = 21;
public bool Bust
{
get { return Bust = Total > blackjack; }
private set { }
}
Actually you're recalculating the total everytime you call the getter of your property.
A solution is to make the field total as Nullable<int> so if it is null, you do the logic you're doing actually otherwise return what is set in the field total.
public class Player
{
private int? total; // <- Nullable<int> here
public int Total
{
get
{
if(total.HasValue) // <- If value is set return that value.
{
return total.Value;
}
total = 0;
foreach (int card in hand)
{
total += card;
}
return total.Value;
}
set { this.total = value; }
}
}
If I were you I would separate the Total calculation and Bust a bit differently:
public class Player
{
public bool Bust { get; set; }
public int GetTotal()
{
if (Bust)
{
return 0;
}
var total = 0;
foreach (int card in hand)
{
total += card;
}
return total;
}
}
A few things to notice:
the calculation is done in a method not a property - i think this is a cleaner way since a property is supposed to be quite simple and not have any logic in it
include Bust in the GetTotal calculation and return 0 if Bust is set to true
always compute the total value, unless you have a very good reason to have a cached version of it
Hope this helps.
Working on a program for class, and am about 95% complete, but have run into a roadblock. I've got a Flight class that holds information about the flight, as well as a seating chart. Using a windows form listbox to select from the flight objects I created by reading from a text file. I can get values for every property from the class object, except for one, SeatChart.
Here's the pertinent code in the main program:
private void lstFlights_SelectedIndexChanged(object sender, EventArgs e)
{
curFlight = (Flight)lstFlights.SelectedItem;
DisplayNewFlightChart();
}
private void DisplayNewFlightChart()
{
int seats = curFlight.Rows * curFlight.Seats;
lstSeatingChart.Items.Clear();
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
}
And here is the code from the class:
class Flight
{
private string mPlane;
private string mDepartureTime;
private string mDestination;
private int mRows;
private int mSeats;
private string[] mSeatChart;
public Flight()
{
}
// Create the overloaded Constructor
public Flight(string planeType, string departureTime,
string destination, int numRows,
int numSeatsPerRow)
{
this.Plane = planeType;
this.DepartureTime = departureTime;
this.Destination = destination;
this.Rows = numRows;
this.Seats = numSeatsPerRow;
this.SeatChart = mSeatChart;
mSeatChart = new string[Rows * Seats];
for (int seat = 0; seat <= mSeatChart.GetUpperBound(0); seat++)
{
mSeatChart[seat] = "Open";
}
}
public string Plane
{
get { return mPlane; }
set { mPlane = value; }
}
public string DepartureTime
{
get { return mDepartureTime; }
set { mDepartureTime = value; }
}
public string Destination
{
get { return mDestination; }
set { mDestination = value; }
}
public int Rows
{
get { return mRows; }
set { mRows = value; }
}
public int Seats
{
get { return mSeats; }
set { mSeats = value; }
}
public string[] SeatChart
{
get { return mSeatChart; }
set { mSeatChart = value; }
}
public void MakeReservation(string passName, int seat)
{
bool seatTaken = false;
if (mSeatChart[seat] != "Open") seatTaken = true;
if (passName != "" && seatTaken == false)
{
mSeatChart[seat] = passName;
}
else
{
MessageBox.Show("Please Enter a Passenger Name, in an unreserved seat");
}
}
It's telling me the curFlight.SeatChart is null, even though I can pull .Rows and .Seats from the curFlight just fine. I have no clue why .SeatChart is messing up. lstFlights is the list of flight objects pulled from the text file, and lstSeatingChart is where I want to display a list of seats.
You are setting SeatChart to mSeatChart, which is null at that time. So no reference to an object is made for this.SeatChart.
After that you initialize mSeatChart and fill it.
You should move setting this.SeatChart after initializing mSeatChart.
mSeatChart = new string[Rows * Seats];
this.SeatChart = mSeatChart;
Edit:
In addition, SeatChart is the property and mSeatChart is the member variable. SeatChart will be used to expose mSeatChart, so it's really weird to set SeatChart with mSeatChart. So weird that I didn't even think you were doing that.
So in your case leave the following out in the constructor:
this.SeatChart = mSeatChart;
I think the actual cause of your issue is somewhere else in the code, where you initiate Flight and fill the list. If I understand correctly you get a null reference error on the concatenation in the for loop?
string[] seatChart = curFlight.SeatChart;
for (int x = 0; x <= seats; x++)
{
lstSeatingChart.Items.Add("Seat " + (x + 1) + " " + seatChart[x]);
}
Check where you initate each Flight object. I bet you are using the empty constructor: new Flight()
Remove the empty constructor, because you don't expect empty values apparently. And if you really need the empty constructor then either initiate all member variables as expected or perform a null check wherever you want to use them.
And once you found the cause, make sure you change the for loop to
for (int x = 0; x < seats; x++)
since you are checking for the number of seats and do a zero-based loop. If x = seats you would have performed the loop seats + 1 times (rows*seats + 1).
If your code relies on a particular property never being null, you need to make sure it is initialized in all constructors.
Based on the logic of your class, I would suggest you shouldn't have a parameter less constructor. It doesn't make sense to have a flight that didn't have a known number of seats (in your implementation at least).
Also some style things.
You don't need to declare your private instance variables. Just use
public string destination {get; set;}
Declare "open" as a class constant and use that constant rather than the hard coded string value.
I'm new to C# and have some trouble with the variable scope.
if(number > 10)
{
int someNr = 5;
}
else
{
/* .... */
}
if(number2 < 50)
{
someNr = 10; /* PRODUCES AN ERROR */
}
else
{
/* ........ */
}
I know that if number is not > 10 then someNr will not be declared as int. But should I wrote two times int someNr? What if both if are true? Double declaration? Is this a problem should I declare the variable outside the if?
Class variables
PHP
class TEST {
private $test = 'test';
private function testVariable(){
/* Not declared */
echo $test;
}
private function testVariable2(){
/* echo 'test' */
echo $this->test;
}
}
C#
class TEST {
private string test = "test";
private void testVariable(){
/* takes the value of class variable test */
test;
}
private function testVariable2(){
/* takes also the value of class variable 'test' */
this.test;
}
}
But what if
C#
class TEST {
private string test = "test";
private void testVariable(){
string test = "somethingOther";
Console.WriteLine(test);
}
}
test is "test" or "somethingOther"?
Which has the priority? The class variable or the local-method variable?
To set the variable inside an if statement you should declare it outside the if statement, otherwise it will be a local variable only available inside the if statement:
int someNr;
if(number > 10)
{
someNr = 5;
}
else
{
/* .... */
}
if(number2 < 50)
{
someNr = 10;
}
else
{
/* ........ */
}
Note: You also need to set some value to the variable in the else blocks, or set an initial value when you define it, otherwise it's not known to always have a value.
In your class TEST the local variable will shadow the class member:
class TEST {
private string test = "test"; // this is a member of the class
private void testVariable(){
string test = "somethingOther"; // this is a local variable that shadows the class member
Console.WriteLine(test); // this will use the local variable, it can't see the class member
}
}
your first example produces an error, because someNr is only defined within the scope of the if statement. You must re-define it in your second if, declaring it as an int.
In your second example, the correct syntax would be Console.WriteLine(test);. Your output would be 'somethingOther', as the test in the inner scope will be used.
Example of Method Scope -- variable someNr is declared within the method (along with number2) and is therefore accessible throughout the method:
public class IntegersTestScope
{
public void TestIntegers(int number)
{
int number2 = 0;
int someNr = 0;
number2 += number;
if (number > 10)
{
someNr = 5;
}
else
{
/* .... */
}
if (number2 < 50)
{
someNr = 10; /* This will no longer PRODUCE AN ERROR */
}
else
{
/* ........ */
}
Console.WriteLine("someNr={0}", someNr.ToString());
}
}
Example of Class Scope -- variable _someNr is declared within the class and are therefore accessible to all methods with that class (Note: variable _someNr is prefixed with underscore character '_' as a naming convention only to denote variable global to class and is not required for code to work):
public class IntegersTestScope
{
private int _someNr = 0;
public void TestIntegers(int number)
{
int number2 = 0;
number2 += number;
if (number > 10)
{
_someNr = 5;
}
else
{
/* .... */
}
if (number2 < 50)
{
_someNr = 10; /* This will no longer PRODUCE AN ERROR */
}
else
{
/* ........ */
}
Console.WriteLine("someNr={0}", _someNr.ToString());
}
}
Is it possible to make attribute which can limit minimum or maximum value of numbers.
Example:
[MinValue(1), MaxValue(50)]
public int Size { get; set; }
and when i do Size = -3; value of Size must be 1.
I searched in Google and can't find single example about this behavior, maybe because it is not possible to make?
I'm gonna use these attributes in property grid therefore having automatic validation can be handy.
Currently I workaround like this to limit minimum value:
private int size;
[DefaultValue(8)]
public int Size
{
get
{
return size;
}
set
{
size = Math.Max(value, 1);
}
}
So this acts like MinValue(1)
Although it is possible to create a custom attribute, attributes are just metadata for the member they annotate, and cannot change its behavior.
So, you won't get the behavior you want with a plain attribute. You need something to process the attributes in order to enact the desired behavior.
Take a look at TypeConverters for a possibility.
Yes, it is possible. Read about custom attributes at MSDN.
And by the way, there is already a solution you can use. It is the RangeAttribute which lets you specify the numeric range constraints for the value of a data field. Read more about it on MSDN.
You can elegantly solve this problem by using PostSharp by writing simple aspect, free version will be enough for this purpose:
[Serializable]
class RangeAttribute : LocationInterceptionAspect
{
private int min;
private int max;
public RangeAttribute(int min, int max)
{
this.min = min;
this.max = max;
}
public override void OnSetValue(LocationInterceptionArgs args)
{
int value = (int)args.Value;
if (value < min) value = min;
if (value > max) value = max;
args.SetNewValue(value);
}
}
and then exacly as you want:
class SomeClass
{
[Range(1, 50)]
public int Size { get; set; }
}
with normal usage:
var c = new SomeClass();
c.Size = -3;
Console.Output(c.Size);
will output 1.
create an extension
public static class Extensions
{
public static int FixedValue(this int value, int min, int max)
{
if (value >= min && value <= max)
return value;
else if (value > max)
return max;
else if (value < min)
return min;
else return 1;
}
}
And then:
private int size;
public int Size { get { return size.FixedValue(1, 50); }
set { size = value.FixedValue(1, 50); } }
Yes, it is possible with (already pointed) CustomAttributes, but mind, that you will loose the comfort of the auto-properties - because you need to apply resp. check the attribute restriction somewhere and in this case an appropriate place would be the getter of the property, so the interesting part of the problem is the application of the attributes. You can read how to access custom attributes in this MSDN article.
A possible solution for the MaxValue custom attribute can look like this:
// simple class for the example
public class DataHolder
{
private int a;
[MaxValue(10)]
public int A
{
get
{
var memberInfo = this.GetType().GetMember("A");
if (memberInfo.Length > 0)
{
// name of property could be retrieved via reflection
var mia = this.GetType().GetMember("A")[0];
var attributes = System.Attribute.GetCustomAttributes(mia);
if (attributes.Length > 0)
{
// TODO: iterate over all attributes and check attribute name
var maxValueAttribute = (MaxValue)attributes[0];
if (a > maxValueAttribute.Max) { a = maxValueAttribute.Max; }
}
}
return a;
}
set
{
a = value;
}
}
}
// max attribute
public class MaxValue : Attribute
{
public int Max;
public MaxValue(int max)
{
Max = max;
}
}
The sample usage:
var data = new DataHolder();
data.A = 12;
Console.WriteLine(data.A);
creates the output:
10
The code for the MinValue will look the same as for the MaxValue but the if condition will be less than instead of greater than.