I want to be able to loop through a Class Property that references its own properties. Why you may ask? Because it's easier to manage later on if I want to add more properties to that Class.
Let me explain more:
public interface IElementBox
{
string Filename { get; }
string FileDefinition { get; set; }
void ExtractFromFile(string stringData);
}
public abstract class Element
{
public Element(string stringData)
{
this.DefFromFile(stringData);
}
public string Name { get; set; }
protected abstract void DefFromFile(string stringData);
}
public class Solid : Element
{
public Solid(string stringData) : base(stringData) { }
public string SolidSpecificProperty { get; set; }
protected override void DefFromFile(string stringData)
{
// Assign SolidSpecificProperty from string
}
}
public class Liquid : Element
{
public Liquid(string stringData) : base(stringData) { }
public string LiquidSpecificProperty { get; set; }
protected override void DefFromFile(string stringData)
{
// Assign LiquidSpecificProperty from string
}
}
public class Gas : Element
{
public Gas(string stringData) : base(stringData) { }
public string GasSpecificProperty { get; set; }
protected override void DefFromFile(string stringData)
{
// Assign GasSpecificProperty from string
}
}
public abstract class ElementBox<T> : IElementBox where T : Element
{
public List<T> Elements { get; set; }
public List<T> GetElementsFromName(string name)
{
return this.Elements.FindAll(x => x.Name == name);
}
public abstract string Filename { get; }
public string FileDefinition { get; set; }
public abstract void ExtractFromFile(string filename);
}
public class SolidBox : ElementBox<Solid>
{
public override string Filename
{
get { return "Solid.txt"; }
}
public override void ExtractFromFile(string stringData)
{
this.Elements.Add(new Solid(stringData));
}
}
public class LiquidBox : ElementBox<Liquid>
{
public override string Filename
{
get { return "Liquid.txt"; }
}
public override void ExtractFromFile(string stringData)
{
this.Elements.Add(new Liquid(stringData));
}
}
public class GasBox : ElementBox<Gas>
{
public override string Filename
{
get { return "Gas.txt"; }
}
public override void ExtractFromFile(string stringData)
{
this.Elements.Add(new Gas(stringData));
}
}
public static class DataDefinition
{
public static SolidBox SolidBox { get; set; }
public static LiquidBox LiquidBox { get; set; }
public static GasBox GasBox { get; set; }
public static IElementBox[] ElementBoxes = new IElementBox[] { DataDefinition.SolidBox, DataDefinition.LiquidBox, DataDefinition.GasBox };
}
public static class Loader
{
public static void LoadInfo()
{
for (int elementBoxNb = 0; elementBoxNb < DataDefinition.ElementBoxes.Length; elementBoxNb++)
{
string dataFilepath = DataDefinition.ElementBoxes[elementBoxNb].Filename;
System.IO.StreamReader sr = System.IO.File.OpenText(dataFilepath);
DataDefinition.ElementBoxes[elementBoxNb].ExtractFromFile(sr.ReadToEnd());
}
}
}
The whole purpose of this structure is to be able to define all the object properties in a text file. So that all the SolidBox.Elements objects are dynamically assigned from that text file definition.
My questions are as follow:
Will the property array in DataDefinition be referenced by value. Which would mean that all my data assignation would get absorbed in the void?
If yes (or no..), is their a better way of doing the whole thing / What would be the best way to do it?
I've been working on that data structure for a while now I'm getting proud of what I could achieve. I would be sad if all that was done for nothing. Although, if one if you can provide me with a better/optimal way of doing the whole thing, I will be grateful and throw my code in my archive folder.
Also, keep in mind that this is an example of the data structure. It does not reflect exactly what my code looks like and is made so to ease comprehension and reading.
Don't hesitate to ask questions if more information is needed.
Deserialization (reading objects in from a persistent medium) has been solved a zillion different ways. Try using Data Contracts, like this answer demonstrates. You just need to add a few attributes to your properties to indicate what you want serialized and then it does just about all of the work for you.
This won't do what you want. The array will contain references to the objects referenced by the properties at the time it is initialised, which in this case will be null. If you assign something to the SolidBox property the associated element of the array won't change, and vice-versa.
Related
I'd like to validate files or entries inside archives (zip, 7z,...) against a database by Crc32.
If files are unknown, delete them. If files need to be renamed, rename them, and so on...
this is the structure that i have implemented so far:
public class FileBase
{
public FileBase() { }
public string FullName { get; set; }
public string Name => Path.GetFileName(FullName);
public string FileNameWithoutExtension => Path.GetFileNameWithoutExtension(FullName);
public string DirectoryName => Path.GetDirectoryName(FullName);
public string Extension => Path.GetExtension(FullName);
public string Crc { get; set; }
public DateTime? LastWriteTime { get; set; }
}
public class FileModel : FileBase
{
public FileModel() { }
public void MoveTo(string target)
public void Delete()
}
public class ArchiveModel : FileModel
{
public ArchiveModel() { }
public HashSet<ArchiveFileModel> Entries{ get; private set; }
public Dictionary<string, Stream> Extract(List<ArchiveFileModel> entries)
public void Compress(Dictionary<string, Stream> fileStreams)
public void Modify(ArchiveInfoFile entry, string targetName)
}
public class ArchiveFileModel : FileBase
{
public ArchiveFileModel() { }
public int Index { get; set; }
public ArchiveModel Parent { get; set; }
}
I now create a list of type FileBase which contains FileModels or ArchiveModels (based on file extension) to loop though every file and validate against database.
The downsite of this, for every needed action (MoveTo, Delete, Extract, Compress, Modify) I need to cast the base class objects into derived class objects (which I feel is bad practise):
var fileList = new List<FileBase>;
.
.
.
foreach (file in fileList)
{
If (file is ArchiveFileModel)
{
var archive = file as ArchiveFileModel;
archive.Compress(....
...
}
}
and so on....
Does anyone have any other ideas to solve this usecase?
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 am trying to make my method generic and I am stuck at a point and need your assistance. The code scenario is I have an abstract class say MyBaseAbs which contains common properties:
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
}
Now I have child classes:
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
}
and another child class:
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
}
Now I have to create a common method which needs to perform some operations on the basis of Mychild1 and Mychild2, so what I did is:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
}
so inside this method I need to write common code which does the mapping for SaveObject object according to the child object passed. How can I determine which object is passed and use properties accordingly.
One option would be to create a base Save function in your base class and make it virtual.
Then override the method in your child classes. This way when you call the Save method in your SaveOperation it should call the appropriate method from the correct child class.
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
public virtual void Save() { }
}
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
public override void Save() {
//Implementation for Mychild1
}
}
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
public override void Save() {
//Implementation for Mychild2
}
}
If you can't modify your business objects, you can check the type of the concrete class in the SaveOperation method:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
if (myObj is Mychild1) {
Mychild1 mychild1 = (Mychild1) myObj;
// Business logic for object of type Mychild1
} else if (myObje is Mychild2) {
Mychild2 mychild2 = (Mychild2) myObj;
// Business logic for object of type Mychild2
}
}
Notice that this is not a very solid solution as, if you are creating new objects that implement your abstract class, you will have to remeber to add another branch in the if statement.
As #BojanB mentioned, the obvious solution would be to create a virtual method in your base class and override it in the derived, but if you cannot modify the code there then you can create a method for each derived class and create a dictionary that maps each type to its method:
private Dictionary<Type, Action<MyBaseAbs, MyCustomClass>> _saveOperations =
new Dictionary<Type, Action<MyBaseAbs, MyCustomClass>>();
//You can then set an entry for each of your derived classes
_saveOperations[typeof(Mychild1)] = (myObj, myCustomObj) =>
{
//Mychild1-specific logic
};
public MyCustomClass SaveOperation(MyBaseAbs obj)
{
//do the common saving operations here
var result = new MyCustomClass();
//....
var actualType = obj.GetType();
if(_saveOperations.ContainsKey(actualType))
{
_saveOperations[actualType](obj, result);
}
return result;
}
You can then add an item to the dictionary for each derived class. It is the same concept as using the is operator but allows you to add methods for more derived types without modifying the original SaveOperation method
You can use C#'s As-Operator as follows:
Mychild1 child1 = myObj as Mychild1;
if(child1 != null) {
//Here you can use child1.Mychild1Prop1 forexample
}
Link to msdn: https://msdn.microsoft.com/en-us/library/cscsdfbt.aspx
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.
I'm not even sure what this principle is called or how to search for it, so I sincerely apologize if it has been brought up before, but the best way to do it is with an example.
class Properties
{
public string Name { get; set; }
}
class MyClass
{
class SubProperties: Properties
{
public override Name
{
get { return GetActualName(); }
set { SetActualName(value); }
}
}
public SubProperties ClassProperties;
private string GetActualName()
{
return SomeFunction();
}
private void SetActualName(string s)
{
ClassProperties.Name = SomeOtherFunction(s);
}
}
The idea is to have any object that instantiates MyClass have a fully accessible property ClassProperties. To that object, it would look exactly like a Properties object, but behind the scenes, MyClass is actually computing and modifying the results of the fields. This method of declaration is obviously wrong since I can't access GetActualName() and SetActualName() from within the SubProperties definition. How would I achieve something like this?
Are you looking for something like this?
abstract class Properties
{
public abstract string Name { get; set; }
}
class MyClass
{
private class SubProperties : Properties
{
private MyClass myClass;
public SubProperties(MyClass myClass)
{
this.myClass = myClass;
}
public override Name
{
get { return this.myClass.GetActualName(); }
set { this.myClass.SetActualName(value); }
}
}
private string name;
public MyClass
{
this.MyClassProperties = new SubProperties(this);
}
public Properties MyClassProperties { get; private set; }
private string GetActualName()
{
return this.name;
}
private void SetActualName(string s)
{
this.name = s;
}
}
You need to pass a reference to a MyClass instance to the SubProperties instance if you want to access MyClass methods from SubProperties.
public virtual string Name { get; set; }