I have a tree (a List<T>) that contains a number of ItemType classes (see code below); the class has the properties OverrideDiscount (which could be null, indicating to use DefaultDiscount (which could be null, indicating to use the parent ItemType's CalculatedDiscount))
So you see I need to recurse up the tree (which incidentally is a List<ItemType>) to get the parent's CalculatedDiscount, because that could be null, which means you need to get the parent's parent's CalculatedDiscount and so on...
Is it a bad idea to put the code for this in the Get accessor?
How would you handle it?
Just as a sidenote, all this data comes via an SqlDataReader from a database in no particular order, then after that the Children property list is populated by looping through the tree and adding to the Children list as appropriate. So the parents are unaware of the children until AFTER the Set accessor has been called, ruling out putting anything useful in the Set accessor (e.g. setting all children's CalculatedDiscount in the Set accessor). Unless I've missed some other way of doing it (very possible, recursion fries my brain sometimes).
Thanks in advance
The class so far:
public class ItemType
{
public int ID;
public int? ParentID;
public List<ItemType> Children;
public double? DefaultDiscount;
public double? OverrideDiscount;
public double CalculatedDiscount
{
get
{
if (OverrideDiscount != null)
{
return (double)OverrideDiscount; //+ Autospec qty
}
else
{
if (DefaultDiscount != null)
{
return (double)DefaultDiscount;
}
else
{
//I need to get this ItemType's parent's discount
//here by recursing up the tree...is this a bad idea?
}
}
}
}
}
Instead of just storing the Id of the Parent item, I would store the complete object. That would make this a lot easier (I would also convert those public variables to properties):
public class ItemType
{
public int Id { get; set; }
public ItemType Parent { get; set; }
public List<ItemType> Children; { get; set; }
public double? DefaultDiscount { get; set; }
public double? OverridenDiscount { get; set; }
public double CalculatedDiscount
{
get
{
return (double)(OverridenDiscount ??
DefaultDiscount ??
(Parent != null ? Parent.CalculatedDiscount : 0));
}
}
}
I don't see any reason why this is not a good idea. Maybe specify it in Xml comments for that property to make sure others are aware of that behavior but if it represents your program's logic then why not.
Properties are normally considered as not doing much. Because of that, I suggest, you create a method GetCalculatedDiscount that does all the traversing.
Related
I am trying to copy a subset of a list to a new list, but can't seem to copy over the custom class properties.
For example, below I have a House class with an int, bool, and Basement property. The Basement property is made up of a double. When I get the list of houses for the List AllHouses property, all the properties are filled. However, when I copy the AllHouses list to the SubjectHouses list (using a lambda statement to only select houses where IsSubjectHouse == true), the MLSNumber and IsSubjectHouse properties copy, but every object in the List has a null HouseBasement property.
It seems like something that should be so simple, but I've tried so many things and searched around in so many ways and can't seem to figure out what I'm doing wrong. Any pointers would be much appreciated. Below is a trimmed down version of the code I'm working with that hopefully gives some context to what I've written above.
public class House
{
public int MLSNumber { get; set; }
public bool IsSubjectHouse { get; set; }
public Basement HouseBasement { get; set; }
}
public class Basement
{
public double SqFt { get; set; }
}
public ViewSubjectHouseViewModel()
{
//This list has all properties
List<House> AllHouses = GetHouseList();
//This list does not bring over the Basement property
List<House> SubjectHouses = AllHouses.FindAll(house => house.IsSubjectHouse == true);
}
I have a (much abbreviated) class like this:
public class Widget
{
public List<Widget> SubWidgets { get; set; }
public Widget ParentWidget { get; set; }
private double _ImportantValue;
public double ImportantValue
{
get { return _ImportantValue; }
set
{
_ImportantValue = value;
RecalculateSubWidgets();
}
}
}
When deserializing, I don't want to RecalculateSubWidgets. What is the best way to handle this situation? The only thing I've been able to come up with so far is to set a "global" variable that says I'm deserializing and skip the call to RecalculateSubWidgets() in that case, but that seems ultra kludgy.
A simple way could be to ignore the current property and use another one for getting the deserialized value:
private double _ImportantValue;
[XmlElement("ImportantValue")]
public double ImportantValueFromXml
{
get { return _ImportantValue; }
set
{
_ImportantValue = value;
}
}
[XmlIgnore]
public double ImportantValue
{
get { return _ImportantValue; }
set
{
_ImportantValue = value;
RecalculateSubWidgets();
}
}
When you deserialize the RecalculateSubWidgets() method won't be called but your private field will still have the value. Of course you might want to change your design a bit and get rid of the function call in the setter to avoid this situation but this can be a short term solution.
I need to change the value of an item of a list returned by a query... It must be simple, but i can´t see it using linq.
The list is composed by elements of this structure:
public struct HeaderButton
{
public string content {get; set;}
public BitmapImage icon {get; set;}
public PageContainerFactory.ContainerType containerType {get; set;}
public bool IsSelected { get; set; }
}
private List<HeaderButton> _headerButtons;
public List<HeaderButton> HeaderButtons
{
get
{
if (_headerButtons == null)
_headerButtons = new List<HeaderButton>();
return _headerButtons;
}
set { _headerButtons = value; }
}
I´ve tried this:
HeaderButtons.First(x => x.containerType == CurrentContainer.CType).IsSelected = true;
And the compiler tells me:
Cannot modify the return value of 'System.Linq.Enumerable.First(System.Collections.Generic.IEnumerable, System.Func)' because it is not a variable
And now the query that i´m trying:
var h = HeaderButtons.First(x => x.containerType == CurrentContainer.CType);
h.IsSelected = true;
I had to take the element in a var because of the compiler error. And doing it as represented in the code above, obviously "h" does not points to the "HeaderButtons" real element since it is a new HeaderButton object and not a reference.
Following your comments, i decided to make a nested class in place of the structure since this kind of objects are not used outside of the content class, and now that is a class (object reference) and not a struct (value), everything works fine.
The code:
sealed class MainViewModel : ViewModelNavigator
{
internal class HeaderButton
{
public string Content { get; set; }
public BitmapImage Icon { get; set; }
public PageContainerFactory.ContainerType ContainerType { get; set; }
public bool IsSelected { get; set; }
}
...
private List<HeaderButton> _headerButtons;
public List<HeaderButton> HeaderButtons
{
get
{
if (_headerButtons == null)
_headerButtons = new List<HeaderButton>();
return _headerButtons;
}
set { _headerButtons = value; }
}
...
HeaderButtons.First(x => x.ContainerType == CurrentContainer.CType).IsSelected = true;
The compiler is saving you from shooting yourself in the foot.
Because HeaderButton is a struct it is passed by value instead of by reference. Which means that the Linq First operator is acting on (and will return) a value copy of the element in the list.
Because the return value from First is not assigned to anything it is temporary and will go out of scope at the end of the statement, and what's more since it is a value copy and not a reference to the item in the list any changes you make to it will not affect the item in the list anyway.
If this were to compile you might easily be misled to thinking that you had updated the item in the list, which you would not have. By refusing to compile the compiler is saving you from having to track down what could be a tricky bug to find.
If you have reason to keep HeaderButton as a struct then a statement like this will enable you to update it.
var hb = HeaderButtons.First(x => x.containerType == CurrentContainer.CType);
HeaderButtons[HeaderButtons.IndexOf(hb)].IsSelected = true;
If you go this route you need to ensure your struct's equality operations behave in a way that is useful to you, which hinges on the same factors as 'If you have reason to keep HeaderButton as a struct' because part of wanting to use a struct instead of a class means wanting value equality instead of reference equality semantics.
I have the next object (Tree structured Object):
public class someClass
{
ObservableCollection<someClass> Children { get; }
long NumOfSelectedChildren { get; set; }
}
//There is more properties but its not important for my question
I need to scan a given "someClass" Object and set for every node into the property NumOfSelectedChildrenthe number Of his children.
I wrote some recursion that do this task but I must send the NumOfSelectedChildren proprty as reference. Currently, when my recursion finished all the "NumOfSelectedChildren" properties are equal to 0 because the recursion move the parameters by value and not by reference.
When I`m trying to send the property as "ref" I get the following error:
"Error 23 A property, indexer or dynamic member access may not be passed as an out or ref parameter"
How can I make sure that this property will be sent by reference and not by value?
Thanks.
You haven't shown how you update the NumOfSelectedChildren property, so let me propose an alternate solution that doesn't require you to pass a property by reference:
public class someClass
{
ObservableCollection<someClass> Children { get; }
long NumOfSelectedChildren { get; set; }
int UpdateNumOfSelectedChildren()
{
return NumOfSelectedChildren =
Children.Sum(x => 1 + x.UpdateNumOfSelectedChildren());
}
}
I have a module that iterates through the public properties of an object (using Type.GetProperties()), and performs various operations on these properties. However, sometimes some of the properties should be handled differently, e.g., ignored. For example, suppose I have the following class:
class TestClass
{
public int Prop1 { get; set; }
public int Prop2 { get; set; }
}
Now, I would like to be able to specify that whenever my module gets an object of type TestClass, the property Prop2 should be ignored. Ideally I would like to be able to say something like this:
ReflectionIterator.AddToIgnoreList(TestClass::Prop2);
but that obviously doesn't work. I know I can get a PropertyInfo object if I first make an instance of the class, but it doesn't seem right to create an artificial instance just to do this. Is there any other way I can get a PropertyInfo-object for TestClass::Prop2?
(For the record, my current solution uses string literals, which are then compared with each property iterated through, like this:
ReflectionIterator.AddToIgnoreList("NamespaceName.TestClass.Prop2");
and then when iterating over the properties:
foreach (var propinfo in obj.GetProperties())
{
if (ignoredProperties.Contains(obj.GetType().FullName + "." + propinfo.Name))
// Ignore
// ...
}
but this solution seems a bit messy and error-prone...)
List<PropertyInfo> ignoredList = ...
ignoredList.Add(typeof(TestClass).GetProperty("Prop2"));
should do the job... just check whether ignoredList.Contains(propinfo)
Could you add attributes to the properties to define how they should be used? eg
class TestClass
{
public int Prop1 { get; set; }
[Ignore]
public int Prop2 { get; set; }
}