I have to classes, Father and Child (by example)
A snippet of my implementation
Class Father.cs
public class Father
{
public int Id { get; set; }
public string Name { get; set; }
public List<Child> Children { get; set; }
public Father()
{
}
}
Class Child.cs
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Child()
{
}
}
I'am trying to do something like this
Father f = new Father();
f.Children[0]; // ok
f.Children[1]; // ok
f.Children["John"]; // Duh!
I now, its wrong, i need to implement something in Child Class, i tryed this
public Child this[string name]
{
get
{
return this;
}
}
But this doesnt work.
How can i implement this feature for my class Child?
A List<T> doesn't have a string indexer; you could add one to the Father class, but the usage will be:
var child = parent["Fred"];
(no .Children)
For the indexer itself: Try (in the indexer):
return Children.FirstOrDefault(c=>c.Name==name);
To get an indexer on the list itself, you would have to create a custom list type and add the indexer there.
IMO, a method may be clearer (on Father):
public Child GetChildByName(string name) {...}
Or you can set it up like this:
public class Father
{
public int Id { get; set; }
public string Name { get; set; }
public Children Children { get; set; }
public Father()
{
}
}
public class Children : List<Child>
{
public Child this[string name]
{
get
{
return this.FirstOrDefault(tTemp => tTemp.Name == name);
}
}
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Child()
{
}
}
Then you call it how you want.
In father class, you could write following code:
public Child this[string name]
{
get
{
return Children.Where(c => c.Name == name);
}
}
and use it like:
Father f = new Father();
f.Children[0]; // ok
f.Children[1]; // ok
f["John"]; // ok!
You are treating the List of Children like a Dictionary (Dictionaries can be accessed by key). Just change your List to a Dictionary and set the string to be the Child's name.
You could make the Children List into an OrderedDictionary so that you can reference it by index or key and then add the objects with the name as the key. Just so you know though, any of these options can run into issues if you have multiple children with the same name.
Related
I've been playing with various ways of using generics and have hit a road block.
Consider the following classes:
public abstract class DataElement
{
public int Id { get; set; }
}
public class School : DataElement
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
}
public class Course : DataElement
{
public int Id { get; set; }
public int SchoolId { get; set; }
public string Name { get; set; } = string.Empty;
}
public class Student : DataElement
{
public int Id { get; set; }
public int CourseId { get; set; }
public string Name { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
Considering a hypothetical scenario where none of this data changes, I'm trying to create a DataDictionary class to house those objects in their respective Lists all within one top-level List property. This crazy idea came to me, when I was writing code to load the different data types from JSON files. I was able to write one load method that could read all three types of data using generics, and that sent me down this particular rabbit hole.
public interface IDataDictionary
{
public List<T> GetAllItemsFromList<T>();
public T GetSingleItemFromList<T>(int id);
}
public class DataDictionary : IDataDictionary
{
public List<IList> Data = new List<IList>();
// Return all objects from the list of type T
public List<T> GetAllItemsFromList<T>()
{
return Data.OfType<T>().ToList(); // This works, returning the appropriate list.
}
// Return specific object from the list of type T by Id property value
public T GetSingleItemFromList<T>(int id)
{
List<T> list = Data.OfType<List<T>>().First(); // This works, resolving to the correct list (e.g. Courses).
return list.Where(i => i.Id == id).First(); // This doesn't work. It doesn't appear to know about the Id property in this context.
}
}
GetAllItemsFromList works fine, returning the appropriate list of items
List<School> newList = GetAllItemsFromList<School>();
However, I am unable to figure out how to return a single item by Id from its respective list.
School newSchool = GetSingleItemFromList<School>(1);
It could be that I'm just trying to be too clever with this, but I can't help but think there is a way to do this, and I'm just missing it.
This doesn't work. It doesn't appear to know about the Id property in this context.
Yes, because you have not specified any constraints to the type parameter T, so it can be anything. There are multiple options:
Create an interface IHaveId and constraint T to it (or use DataElement):
public interface IHaveId
{
int Id { get; set; }
}
public interface IDataDictionary
{
public List<T> GetAllItemsFromList<T>();
public T GetSingleItemFromList<T>(int id) where T : IHaveId; // or where T : DataElement
}
public class DataDictionary : IDataDictionary
{
public T GetSingleItemFromList<T>(int id) where T : IHaveId // or where T : DataElement
{
List<T> list = Data.OfType<List<T>>().First();
return list.Where(i => i.Id == id)
.First();
}
}
add additional parameter to select the id:
public T GetSingleItemFromList<T>(int id, Func<T, int> idSelector)
{
List<T> list = Data.OfType<List<T>>().First();
return list.First(i => idSelector(i) == id);
}
use reflection - I would argue the least recommended option
The problem is that T parameter in function GetSingleItemFromList<T>(int id) could be anything. In order of this to work you should add a constraint:
GetSingleItemFromList<T>(int id) where T: DataElement
I'm writing a tool which accesses a word document to prefill it with data. The document has a subset of custom document properties, each identified by a name, whose values are used to update fields in the document.
My ViewModel should both be able to initiate/update its instances from data of those document properties, aswell as write its values back and update the fields of the document.
Something like this:
class PersonVM : INotifyPropertyChanged
{
// properties
string Name { get; set; }
string PhoneNumber { get; set; }
// methods to get data or save data of this properties to or from the word document
void saveMyPropertyValuesToWord()
{
// …
}
void updateMyPropertiesFromWord()
{
// …
}
}
class ProjectVM : INotifyPropertyChanged
{
int ProjectNumber { get; set; }
PersonVM Manager { get; set; }
PersonVM Mechanic1 { get; set; }
PersonVM Mechanic2 { get; set; }
void saveMyPropertyValuesToWord()
{
Manager.saveMyPropertyValuesToWord();
Mechanic1.saveMyPropertyValuesToWord();
Mechanic2.saveMyPropertyValuesToWord();
// handle ProjectNumber etc.
}
void updateMyPropertiesFromWord()
{
Manager.updateMyPropertiesFromWord();
Mechanic1.updateMyPropertiesFromWord();
Mechanic2.updateMyPropertiesFromWord();
// handle ProjectNumber etc.
}
class CompanyVM : INotifyPropertyChanged
{
string Name { get; set; }
PersonVM Owner { get; set; }
ProjectVM Project1 { get; set; }
ProjectVM Project2 { get; set; }
// …
}
// …
}
Right now I have a class with static string properties for each document property that might be present in a word document from which I would like to load the data accordingly:
class WordUtils
{
// Company
static string CompanyName = "dp_CompanyName";
// Company.Owner
static string CompanyOwnerName = "dp_CompanyOwnerName";
static string CompanyOwnerPhone = "dp_CompanyOwnerPhone";
// Company.Project1
static string CompanyProject1Number = "dp_CompanyProject1Number";
// Company.Project1.Manager
static string CompanyProject1ManagerName = "dp_CompanyProject1ManagerName";
static string CompanyProject1ManagerPhone = "dp_CompanyProject1ManagerPhone";
// Company.Project1.Mechanic1
// … etc
}
Now back to implementing those PersonVM.saveMyPropertyValuesToWord() - I thought of something like this:
void saveMyPropertyValuesToWord()
{
Name = MyApp.MyWordDocument.GetCustomProperty(WordUtils.OwnerName);
}
but here I need to know on class Level exactly what instance of it this is called from (i.e. what PersonVM am I, Company.Owner or Project1.Manager or ?) in order to decide which WordUtils.Name I need to provide.
I'm not sure how this should be done, maybe make PersonVM abstract and make a new class for each role (which would again only have one instance of itself, not very pretty in my eyes)? I have also taken a short look at Attributes and expect those might be helpfull in this scenario. Maybe I am missing something obvious, but extensive search for a robust way to tackle this problem have been fruitless so far.
How about something like this:
class Property
{
public string Key { get; }
public string Value { get; set; }
public Property(string key) => Key = key;
}
interface IPropertyTree
{
IEnumerable<IPropertyTree> ChildNodes { get; }
IEnumerable<Property> Properties { get; }
}
class PersonVM : IPropertyTree
{
private readonly string prefix;
public PersonVM(string prefix)
{
Name = new Property(prefix + "Name" );
PhoneNumber = new Property(prefix + "PhoneNumber");
}
public Property Name { get; }
public Property PhoneNumber { get; }
public IEnumerable<IPropertyTree> ChildNodes => Enumerable.Empty<IPropertyTree>();
public IEnumerable<Property> Properties => new[] {Name, PhoneNumber};
}
static class PropertyTreeExtensions
{
public static void Update(this IPropertyTree self)
{
foreach (var property in self.Flatten().SelectMany(tree => tree.Properties))
{
property.Value = MyApp.MyWordDocument.GetCustomProperty(property.Key);
}
}
public static IEnumerable<IPropertyTree> Flatten(this IPropertyTree self)
{
var stack = new Stack<IPropertyTree>();
stack.Push(self);
while (stack.Count > 0)
{
var current = stack.Pop();
yield return current;
foreach (var child in current.ChildNodes)
{
stack.Push(child);
}
}
}
}
This should allow each property to have a unique key, and keep the key and property value tightly coupled. It should also allow you to move the save/update logic to a centralized place.
Of course you can implement a concrete class of IPerson for each type and hard code the individual implementations.
Since you know the person type the moment you are creating an instance of PersonVMM, you could add an attribute PersonTypeId and set it from the constructor,
void SomeMethod()
{
var personVm = new PersonVM(WordUtils.OwnerName);
}
class PersonVM : INotifyPropertyChanged
{
// properties
string PersonTypeId { get; set; }
string Name { get; set; }
string PhoneNumber { get; set; }
public PersonVM()
{}
public PersonVM(string personTypeId)
{
PersonTypeId = personTypeId;
}
// methods to get data or save data of this properties to or from the word document
void saveMyPropertyValuesToWord()
{
Name = MyApp.MyWordDocument.GetCustomProperty(PersonTypeId);
}
}
I have a class that tracks relations between owner classes. The tree can potentially be infinite--in the DB, each record has a parent ID that is a self-reference to the same table. The class basically looks like this:
public class ObjectRelation
{
public ObjectRelation(GetObjectParentChildList_Result relation)
{
this.ObjectId = relation.Object_ID;
this.ParentObjectId = relation.Parent_Object_ID;
this.ChildObjects = new List<ObjectRelation>();
}
public int ObjectId { get; set; }
public int? ParentObjectId { get; set; }
public List<ObjectRelation> ChildObjects { get; set; }
}
I'd like a way given a reference to a single instance of this class to end up with a list of every unique ID in the tree in one list to ensure that as a user is entering data they don't create a infinite parent/child loop (ie, IDs 1 & 2 being parents of each other) and it looks as though SelectMany is the way to go. Is such a query feasible in LINQ, or am I stuck writing a separate method to recurse down the whole tree and return the calculated list of IDs once I run out of child nodes?
public class ObjectRelation
{
public ObjectRelation(GetObjectParentChildList_Result relation)
{
this.ObjectId = relation.Object_ID;
this.Parent = relation.Parent_Object;
this.ChildObjects = new List<ObjectRelation>();
}
public int ObjectId { get; set; }
public ObjectRelation Parent { get; set; }
public List<ObjectRelation> ChildObjects { get; set; }
}
public static class ObjectRelationExtensions
{
public static IEnumerable<ObjectRelation> Parents(this ObjectRelation obj)
{
while(obj.Parent!=null)
{
obj = obj.Parent;
yield return obj;
}
}
}
Then to check:
if (x.Parents.Any(p=>p==x)) throw Exception();
or
if (x.Parents.Any(p=>p.ObjectId==x.ObjectId)) throw Exception();
Im trying to set a parent class property in child property setter.
I have one main class :User, which has a child class LIST ArrayPositions, which in turn has a child class list of ExpressionMember.
Whenever the property ExpressionMemValue in ExpressionMember class is set, i want to update it's parent class ArrayPosition aswell.
However the current solution does not update the corresponding parent.
Here's the code:
public List<User> users = new List<User>();
public class User
{
public string ImageName { get; set; }
private string _PartName = "";
public string PartName
{
get
{
return this._PartName;
}
set {
_PartName=value;
}
}
public List <ArrayPosition> ArrayPositions { get; set; }
public override string ToString()
{
return this.PartName.ToString();
}
}
public class ArrayPosition:User
{
public string myArrayPos = "";
public string PartId { get; set; }
public string ArrayPos
{
get
{
return this.myArrayPos;
}
set
{
this.myArrayPos = value;
}
}
public List<ExpressionMember> ExpressionMembers { get; set; }
}
public class ExpressionMember : ArrayPosition
{
public string ExpressionMem { get; set; }
public string MyExpressionMemValye="";
public string ExpressionMemValue
{
get
{
return MyExpressionMemValye;
}
set
{
MyExpressionMemValye = value;
// this.ArrayPos = value; //set parent value, this will not update it
}
}
}
It would appear that you need to not use inheritance and instead use composition which you are kind of already doing. Try doing this instead. It's not perfect by any means but I'm trying not to change your general strategy too much.
public class User
{
public string ImageName { get; set; }
private string _PartName = "";
public string PartName
{
get
{
return this._PartName;
}
set {
_PartName=value;
}
}
public List <ArrayPosition> ArrayPositions { get; set; }
public override string ToString()
{
return this.PartName.ToString();
}
}
public class ArrayPosition
{
public string myArrayPos = "";
public string PartId { get; set; }
public string ArrayPos
{
get
{
return this.myArrayPos;
}
set
{
this.myArrayPos = value;
}
}
public List<ExpressionMember> ExpressionMembers { get; set; }
}
public class ExpressionMember
{
private ArrayPosition _parentArrayPosition;
public string ExpressionMem { get; set; }
public string MyExpressionMemValye="";
public string ExpressionMemValue
{
get
{
return MyExpressionMemValye;
}
set
{
MyExpressionMemValye = value;
this._parentArrayPosition.ArrayPos = value;
}
public ExpressionMember(ArrayPosition parent) {
_parentArrayPosition = parent;
}
}
}
You are definitely not using inheritance and composition correctly. You are looking to build a tree of objects where the object itself has child objects. Something that might clarify things in your mind is instead of calling them child/parent classes, refer to them as sub/super classes in the case of inheritance and parent/child objects in the case of composition. A parent object is an instance of a class that contains another instance of a class (child object). A subclass inherits the members of another class.
Your inheritance is very strange. The exact responsibilities of your classes are not clear to me.
Apart from that, you could protect the property ExpressionMembers by making it read-only. Implement a new method to add or remove elements. Add an event (e.g. ExpressionMemValueChanged) to ExpressionMember . This event is triggered when an item is added. Whenever an element is added or removed you register/deregister ArrayPosition to/from this event. Inside the event handler you can then set your ArrayPos value.
(You can use an ObservableCollection for your ExpressionMembers and react to the CollectionChanged event instead of writing a getter/setter.)
I am having some class like
public class Employee
{
public List<Employee> ChildOrg{get; set;}
public string name {get; set;};
public string id{get; set;};
public string parentid{get; set;};
}
Now in project I am having the object of Employee that contains the actual hierarchy to display in TreeView.
Now to give this object TreeView i need to give IHierarchicalEnumarable type reference.
So how can i convert my Modal to IHierarchicalEnumrable and give it to TreeView?
I already used following link.
http://www.codeproject.com/Articles/19639/Implementing-IHierarchy-Support-Into-Your-Custom-C
In above link i am specially confused about "GetChildern" and "GetParent" method i am unable to understand how it can fit in my requirement where i am already having hierarchy.
I am unable to understand please help me to understand how it works.
Finally found out how I can use IHierarchicalEnumerable.
Please check out following. Modified my model class like this:
public class Employee : IHierarchyData
{
public EmployeeCollection ChildOrg { get; set; }
public string name { get; set; }
public string id { get; set; }
public IHierarchicalEnumerable GetChildren()
{
return ChildOrg as IHierarchicalEnumerable;
}
public System.Web.UI.IHierarchyData GetParent()
{
return null;
}
public bool HasChildren
{
get { return ((this.ChildOrg != null) && (this.ChildOrg.Count > 0)); }
}
public object Item
{
get { return this; }
}
public string Path
{
get { return this.id; }
}
public string Type
{
get { return this.GetType().ToString(); }
}
}
Added new class as follows:
public class EmployeeCollection : List<Employee>, IHierarchicalEnumerable
{
public IHierarchyData GetHierarchyData(object enumeratedItem)
{
return enumeratedItem as IHierarchyData;
}
}
And used recursive function to create hierarchy.