Problem: I am trying to update a List. If a certain item's ID already exists in the List, I want to add onto that item's quantity. If not, then I want to add another item to the list.
cart = (List<OrderItem>)Session["cart"];
for(int counter = cart.Count-1; counter >= 0; counter--)
{
if (cart[counter].productId == item.productId)
{
cart[counter].productQuantity += item.productQuantity;
}
else if (counter == 0)
{
cart.Add(item);
}
}
cart[counter] and item represent an instance(s) of a custom object of mine. Currently when I finally find a matching ID, everything APPEARS as though it should work, but I get a StackOverflowException thrown in my custom object class.
public int productQuantity
{
get
{
return _productQuantity;
}
set
{
productQuantity = value;
}
}
It gets thrown right at the open-bracket of the "set". Could somebody please tell me what the heck is wrong because I've been going at this for the past 2+ hours to no avail. Thank you in advance.
the problem is in your setter of the productQuantity
it should read:
set
{
_productQuantity= value;
}
edit (naming convention):
public class Vertex3d
{
//fields are all declared private, which is a good practice in general
private int _x;
//The properties are declared public, but could also be private, protected, or protected internal, as desired.
public int X
{
get { return _x; }
set { _x = value; }
}
}
Replace productQuantity = value; with _productQuantity = value; (you're recurring infinitely by calling the setter over and over)
Why not just use this instead?
public int productQuantity { get; set; }
But the flaw was in the _
public int productQuantity {
get {
return _productQuantity;
}
set {
_productQuantity = value;
}
}
cart = (List<OrderItem>)Session["cart"];
int index = cart.Find(OrderItem => OrderItem.productId == item.productId);
if(index == -1) {
cart.Add(item);
} else {
cart[index].productQuantity += item.productQuantity;
}
public int productQuantity
{
get
{
return _productQuantity;
}
set
{
_productQuantity = value; //this should be an assignment to a member variable.
}
}
Related
I know, the title is bad, but I couldn't think if a better one. The question is very specific.
Ok, so I'm using a class in my game identical to Odin Inspector's example RPG Skills classes. But it's set up in a way I don't quite understand and I can't work out how to set the value (I can get it, and there is a setter, so it's possible to set too). Also, all the skill classes/structs/etc are in the same .cs file.
The SkillList function I use to get the Value:
(I get it with skills[Strength].Value; in other classes)
public int this[SkillType type]
{
get
{
for (int i = 0; i < this.skills.Count; i++)
{
if (this.skills[i].Type == type)
return this.skills[i].Value;
}
return 0;
}
set
{
for (int i = 0; i < this.skills.Count; i++)
{
if (this.skills[i].Type == type)
{
var val = this.skills[i];
val.Value = value;
this.skills[i] = val;
return;
}
}
this.skills.Add(new SkillValue(type, value));
}
}
SkillValue struct:
[Serializable]
public struct SkillValue : IEquatable<SkillValue>
{
public SkillType Type;
public int Value;
public SkillValue(SkillType type, int value)
{
this.Type = type;
this.Value = value;
}
public SkillValue(SkillType type)
{
this.Type = type;
this.Value = 0;
}
public bool Equals(SkillValue other)
{ return this.Type == other.Type && this.Value == other.Value; }
}
SkillType enum:
public enum SkillType
{
Science,
Technology,
Arts,
Language,
}
I've tried:
skills[Science].Value = 10;
skills[Science] = new SkillValue(Science, 10);
skills[Science, 10]; (using a new function made by me)
skills[Science](10);
skills[Science].Value(10);
skills[Science] = 10;
But none work, and I'm just guessing randomly now.
How can I set the value?
Thanks
The solution:
character.skills[Rorschach.Character.Skills.SkillType.Science] = value;
Your property is of type int and expects a key of type SkillType so it should probably be
SkillList skills;
skills[SkillType.Science] = 10;
actually also
I get it with skills[Strength].Value;
seems odd with the code you provided. As said the property returns an int which has no property Value so it should actually be
int x = skills[SkillType.Strength];
Now knowing the full implementation code and your actual usage:
public SkillList skills;
...
public int Science
{
get { return this.Character.skills[Science].Value; }
set { this.Character.skills[Science].Value(10); }
}
ATTENTION!
What you did here by accident is using the other property
public SkillValue this[int index]
{
get { return this.skills[index]; }
set { this.skills[index] = value; }
}
which takes an int index and returns a SkillValue.
BUT you are causing a runtime StackOverlowExeption due to a recursive call of Science.
You can't use Science inside of the getter or setter of equally called property!
Imagine using the getter as example:
You would call
var test = Science;
so it executes the getter
return Character.skills[Science].Value;
but well ... in order to know the value of Science in order to use it here as the index it would again have to execute the getter so again
return Character.skills[Science].Value;
and by now you hopefully get what I mean.
Solution
You property should actually as guessed before rather look like
public int Science
{
get { return Character.skills[SkillType.Science]; }
set { Character.skills[SkillType.Science] = value; }
}
I may not have a good grasp of the ?? operator yet and ran into a design flaw I couldn't explain.
Compare the following two properties, the only difference being how there are initialized: the first explicitly initialized, while the second with the ?? operator (or am I doing it wrong here?).
If I run data init with both properties, the collection based on the first property comes up populated as expected, while the second one with the ?? operator never gets populated and comes up with 0 elements in the collection.
Surely something is wrong here in my assumption; what is the flaw here?
P.S. Please ignore the Set method which is to implement INotifyPropertyChanged in the base class and has no bearing on this issue (which is confined to the type of initialization).
// property version 1
private ObservableCollection<UserName> _userNameColl = new ObservableCollection<UserName>();
public ObservableCollection<UserName> UserNameColl
{
get { return _userNameColl; }
set { Set(ref _userNameColl, value); }
}
// property version 2
private ObservableCollection<UserName> _userNameColl;
public ObservableCollection<UserName> UserNameColl
{
get { return _userNameColl ?? new ObservableCollection<UserName>(); }
set { Set(ref _userNameColl, value); }
}
// a simple class for creating object collection
public class UserName
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
// a simple test populating the collection
for (int i = 0; i < 4; i++)
{
// silly data init just for test
UserNameColl.Add(new UserName()
{
Name = $"UserName No {i}",
Age = 20 + i,
Email = $"email{i}#local.lan"
});
}
The second one never initializes your field but always returns a new collection. Try this one instead:
public ObservableCollection<UserName> UserNameColl
{
get { return _userNameColl ?? (_userNameColl = new ObservableCollection<UserName>()); }
set { Set(ref _userNameColl, value); }
}
I Have a model SupplierInvoice as follows:
public class SupplierInvoice
{
public bool Use { get; set; }
public ApInvoice Invoice { get; set; }
}
And a ViewModel with a list of this model:
private List<SupplierInvoice> _SupplierInvoices;
public List<SupplierInvoice> SupplierInvoices
{
get
{
return this._SupplierInvoices;
}
set
{
if (this._SupplierInvoices != value)
{
this._SupplierInvoices = value;
this.RaisePropertyChanged("SupplierInvoices");
}
}
}
within this ViewModel I have a calculated property too:
public decimal ApTotal
{
get
{
decimal total = 0;
if (this.SupplierInvoices != null)
{
foreach (SupplierInvoice invoice in this.SupplierInvoices)
{
if (invoice.Use)
{
total += invoice.Invoice.MthInvBal1;
}
}
}
return total;
}
}
this calculated property returns the sum of the balance of all the invoices (if the invoice's Use property is true). The Use property is selected to be true on the view with a checkbox in a grid.
Now... the question is: How do I NotifyPropertyChanged of this calculated property (ApTotal) when the Use property of the SupplierInvoice model has been changed?
I think replacing your List<TObject> by an ObservableCollection<TObject> will do the trick.
From what I remember the List isn't propagating the PropertyChangedEvent to the UI thread.
This may be a bit naughty, but you could always do this:
private List<SupplierInvoice> _SupplierInvoices;
public List<SupplierInvoice> SupplierInvoices
{
get
{
return this._SupplierInvoices;
}
set
{
if (this._SupplierInvoices != value)
{
this._SupplierInvoices = value;
this.RaisePropertyChanged("SupplierInvoices");
this.RaisePropertyChanged("ApTotal");
}
}
}
Whenever you have a calculated property, you just need to raise the INotifyPropertyChanged.PropertyChanged event from the other properties that are involved in the calculation. So as your ApTotal property is calculated from just the SupplierInvoices property, then you can just notify the interface from that property setter:
public List<SupplierInvoice> SupplierInvoices
{
get
{
return this._SupplierInvoices;
}
set
{
if (this._SupplierInvoices != value)
{
this._SupplierInvoices = value;
this.RaisePropertyChanged("SupplierInvoices");
this.RaisePropertyChanged("ApTotal");
}
}
}
Finding an Index of a Class:
The only way I know to find an index of List is
int index = listEmployee.FindIndex(
delegate(Employee findEmployee)
{
return findEmployee.Name.Equals(findName, StringComparison.Ordinal);
});
I was wondering how to add the option to use
int indexT = listEmployee.FindIndex(r >= r.Name == findName);
Or basically what I'm doing wrong that I can't use it.
class Employee
{
private string _name; private int _idNumber;
private string _deptarment; private string _position;
public Employee()
{
_name = ""; _idNumber = 0; _deptarment = ""; _position = "";
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public int IdNumber
{
get { return _idNumber; }
set { _idNumber = value; }
}
public string Department
{
get { return _deptarment; }
set { _deptarment = value; }
}
public string Position
{
get { return _position; }
set { _position = value; }
}
}
I was wondering how to add the option to use
int indexT = listEmployee.FindIndex(r >= r.Name == findName);
That's fine, apart from the syntax problem at r >= which should be r =>
So this works:
int indexT = listEmployee.FindIndex(r => r.Name == findName);
See: Lambda Expressions
int indexT = listEmployee.FindIndex(r => r.Name == findName);
should work. Perhaps you are missing the using System.Linq referece
Not entirely sure what you're trying to accomplish, but a simple List collection is not going to ensure order or sort, so the index (especially if the collection is going to be expected to change) is not a reliable means of accessing a specific object.
If index / order is important, maybe look at a different collection type, such as the Sorted list: http://msdn.microsoft.com/en-us/library/system.collections.sortedlist.aspx
If you're just trying to find a specific object, you can use Linq and just go something like:
listEmployee.Where( r => r.Name == findName );
I have the following class:
public class test
{
private int i;
public test(int in)
{
i = in;
}
public int testint;
{
get { return i; }
set { i = testint; }
}
}
And the following code:
test[] data = new test[3];
for(int j = 0; j < 3; j++)
{
data[i] = new test(0);
data[i].testint = int.Parse(Console.ReadLine());
}
Console.WriteLine(test[0].testint);
Console.WriteLine(test[1].testint);
Console.WriteLine(test[2].testint);
When I run this program and type in 1, 2, 3 as the input, the output is 0, 0, 0. I don't understand why the get or set seem to be not working. If I initialize the array elements with a value other than 0, the output will be that. The data[i].testint = int.Parse(Console.ReadLine()); seems to not be working. How would I go about doing something like that?
Change the set method to this:
public int testint
{
get { return i; }
set { i = value; }
}
You setter is incorrect. It should be:
set { i = value; }
You had:
set { i = testint; }
Which only triggers the getter, which gets from i, so in the end your setter was doing i = i .
In a setter, the value keyword contains the new candidate value for the property. value's type equals the property's. I say candidate value because you can validate it and choose to not apply it.
In your case, you were not applying the value.
Update
Also, when defining getters and setters, no semicolon should be used. Code, then, would look like this:
public int testint
{
get { return i; }
set { i = value; }
}
I see two errors in this code:
public int testint;
{
get { return i; }
set { i = testint; }
}
There should be no semicolon after testint at the top. Also, set needs to assign using value, like this:
public int testint
{
get { return i; }
set { i = value; }
}
Change your setter to say:
set { i = value; }
value corresponds to the value you send to set the variable.
Here's simple way.
public int TestInt {get; set;}