I have an object myBook.
Can I implement a better structure for that kind of data?
public class myRow{
public int ID = 0;
public int number = 0;
public String param1 = null;
public decimal param2 = null;
public string parm3 = "";
public int param4 = null;
}
public class mySubChapter{
public int ID = 0;
public string title = "";
public List<myRow> rows;
internal bool sort(){...} //sort rows by ID
}
public class myChapter{
public int ID = 0;
public string title = "";
public List<mySubChapter> subChapters;
internal bool sort(){...} //sort subChapters by ID
}
public class myBook{
public int ID = 0;
public string title = ""
public List<myChapter> chapters;
internal bool sort(){...} //sort chapters by ID
}
If you really want to model your book structure in a tree, you could use a generic tree implementation like the one presented here. Then, you could form a tree using code like this
DTreeNode<string> root = new DTreeNode<string>();
DTreeNode<string> temp;
temp = root.Nodes.Add("Hello");
temp.Nodes.Add("olleH");
temp = root.Nodes.Add("World");
temp.Nodes.AddRange(new string[]
{ "dWorl", "ldWor", "rldWo", "orldW" } );
In my opinion, I'll merge subchapter and chapper class into one myChaper class and add new property is chapterLevel in it. Because I think subChapter is a chapter too with just difference level(children of chapter may be). Sorry for my English.
public class myRow{
public int ID = 0;
public int number = 0;
public String param1 = null;
public decimal param2 = null;
public string parm3 = "";
public int param4 = null;
}
public class myChapter{
public int ID = 0;
public string title = "";
public int chapterLevel = 0;
internal bool sort(){...} //sort chapters by ID and level
}
public class myBook{
public int ID = 0;
public string title = ""
public List<myChapter> chapters;
internal bool sort(){...} //sort chapters by ID
}
Another tree implementation:
public interface INode
{
int Id { get; set; }
INode Parent { get; }
ReadOnlyCollection<INode> Children { get; }
void SetParent(INode node);
void AddChild(INode node);
}
public class Node : INode
{
private INode _parent;
private IList<INode> _children;
public Node()
{
_children = new List<INode>();
}
public int Id { get; set; }
public INode Parent
{
get { return _parent; }
}
public ReadOnlyCollection<INode> Children
{
get
{
return new ReadOnlyCollection<INode>
(_children.OrderBy(c => c.Id).ToList());
}
}
public virtual void AddNode(INode node)
{
_children.Add(node);
node.SetParent(this);
}
public virtual void SetParent(INode node)
{
_parent = node;
}
}
The classes, Row, Chapter, Book can derive from the Node class, e.g.
public class Book : Node
{
public override void SetParent(INode node)
{
throw new InvalidOperationException();
}
public string Title { get; set; }
}
Related
My classes are similar to these:
public class Root<TChild>
{
int ID {get;}
...
List<TChild> Children {get;}
}
public class Child
{
int IDChild {get;}
...
}
I need to add the reverse navigation property in Child class to access from Child its Root, but I don't know how to declare the property of Root<TChild> type.
Which type should be TChild in Child class?
I tried this in .net fiddle and seems to work just fine
public class Root<TChild>
{
int ID {get;}
List<TChild> Children { get; set; }
}
public class Child
{
int IDChild {get;}
Root<Child> MyRoot { get; set; }
}
// wherever
var root = new Root<Child> { Children = new List<Child>() };
root.Children.Add(new Child { MyRoot = root });
This works fine and problem is that you have two classes for same entry better is use one class for every entry in tree.
public class TreeEntity
{
private int id = 0;
private TreeEntity parent = null;
private IList<TreeEntity> childs = new List<TreeEntity>();
public TreeEntity(int id)
{
this.id = id;
}
public void AddChild(TreeEntity child)
{
childs.Add(child);
child.parent = this;
}
}
or maybe
public class TreeEntity<T>
{
private int id = 0;
private TreeEntity<T> parent = null;
private IList<TreeEntity<T>> childs = new List<TreeEntity<T>>();
private T data = null;
public TreeEntity(int id, T data)
{
this.id = id;
this.data = data;
}
public void AddChild(TreeEntity<T> child)
{
childs.Add(child);
child.parent = this;
}
}
however in your case
public class Root<TChild>
{
int ID {get;}
...
List<TChild> Children {get;}
...
public void addChild(T child)
{
Children.add(child)
child.setParent(this)
}
}
public class Child
{
int IDChild {get;}
Root<Child> parent;
...
public void setParent (Root<Child>)
{
this.parent = parent;
}
}
I'm having issues trying to pass a list as an argument. I'm not sure what I'm doing wrong. In the following I have an AssociatedTexts list that I am adding to a Books list with the addBook function. The AssociatedTexts that are being selected aren't being saved and assigned to that specific list item in the Books list.
Book dictionary = new Book(ID, textBox1.Text, Product.AssociatedTexts);
Inventory.addBook(dictionary);
The addBook function looks like this:
public static void addBook(Book dictionary)
{
Books.Add(dictionary);
}
And here's the constructor for Book:
public Book(int bookID, string name, BindingList<Book> assocText)
{
BookID = bookID;
Name = name;
AssociatedTexts = assocText;
}
You requested the entire Book class so here it is:
public class Book
{
public static BindingList<Text> AssociatedTexts { get; set; }
public string Name { get; set; }
public int BookID { get; set; }
public int TextID { get; private set; }
public Book()
{
}
public Book(int bookID, string name)
{
BookID = productID;
Name = name;
}
public Book(int bookID, string name, BindingList<Text> assocText)
{
BookID = bookID;
Name = name;
AssociatedTexts = assocText;
}
public static void addAssociatedTexts(Text text)
{
AssociatedTexts.Add(text);
}
public static bool removeAssociatedText(int textID)
{
bool ret = false;
if (Book.AssociatedTexts.Count > textID)
{
Book.AssociatedTexts.RemoveAt(textID);
ret = true;
}
else
{
ret = false;
}
return ret;
}
public Part lookupAssociatedTexts(int searchPart)
{
for (int i = 0; i < AssociatedTexts.Count; i++)
{
if (AssociatedTexts[i].TextID == searchPart)
{
return AssociatedTexts[i];
}
}
return null;
}
What I am trying to accomplish is for each entry in the list of Books to have it's own list of AssociatedTexts. I am mapping these onto datagridviews and the user is able to add their own books with their own varying associatedtexts onto it but I am having trouble associating each associatedtexts list with each Book
As each book shall have its own list of associated texts, AssociatedTexts must not be static. Otherwise, all books will share the same list.
Also, I suggest to replace BindingList by List as Book is a typical model class and should not contain such UI-related members.
public class Book
{
public List<Text> AssociatedTexts { get; set; }
public string Name { get; set; }
public int BookID { get; set; }
public Book(int bookID, string name, IEnumerable<Text> assocText)
{
BookID = bookID;
Name = name;
AssociatedTexts = assocText.ToList();
}
public void addAssociatedText(Text text)
{
AssociatedTexts.Add(text);
}
public bool removeAssociatedText(int textID)
{
bool ret = false;
if (AssociatedTexts.Count > textID)
{
AssociatedTexts.RemoveAt(textID);
ret = true;
}
else
{
ret = false;
}
return ret;
}
public Part lookupAssociatedTexts(int searchPart)
{
for (int i = 0; i < AssociatedTexts.Count; i++)
{
if (AssociatedTexts[i].TextID == searchPart)
{
return AssociatedTexts[i];
}
}
return null;
}
}
I have this class that i want to serialize to a XML file. I want to add a "Description" attribute to each property of the class like below. Is it possible? Or how can i achieve this?
[Serializable]
public class Arm : INotifyPropertyChanged{
private int _ID;
private ArmStore _aStore;
private ArmDimension _dimension;
private Zone _accessibleZone;
[XmlElement("ID")]
[XmlAttribute("description"), Value="It defines ID number of the Arm"]
public int ID {
get { return _ID; }
set { _ID = value; }
}
[XmlElement("Store")]
[XmlAttribute("description"), Value="It defines the Store of the Arm"]
public ArmStore aStore {
get { return _aStore; }
set {
_aStore = value;
Notify("aStore");
}
}
[XmlElement("Dimension")]
[XmlAttribute("description"), Value="It defines the dimension of the Arm"]
public ArmDimension dimension {
get { return _dimension; }
set {
_dimension = value;
Notify("dimension");
}
}
I want to have the following result:
<ID description="It defines ID number of the Arm">1</ID>
<Dimension description="It defines the dimension of the Arm">
<XMin>-150</XMin>
<XMax>150</XMax>
<YMin>-300</YMin>
<YMax>300</YMax>
</Dimension>
Thanks in advance!
You can create custom attribute
[AttributeUsage(AttributeTargets.Property)]
public class XmlDescription : Attribute
{
public string Value { get; set; }
}
and set it on the desired properties
public class Arm
{
[XmlElement("ID")]
[XmlDescription(Value = "It defines ID number of the Arm")]
public int ID { get; set; }
[XmlElement("Store")]
[XmlDescription(Value = "It defines the Store of the Arm")]
public ArmStore Store { get; set; }
[XmlElement("Dimension")]
[XmlDescription(Value = "It defines the dimension of the Arm")]
public ArmDimension Dimension { get; set; }
}
Next, you need to create a custom XmlWriter
public class DescriptionWriter : XmlTextWriter
{
public DescriptionWriter(string filename, Encoding encoding) : base(filename, encoding) { }
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix, localName, ns);
var prop = typeof(Arm).GetProperty(localName);
if (prop != null)
{
var data = prop.GetCustomAttributesData();
var description = data.FirstOrDefault(a => a.AttributeType == typeof(XmlDescription));
if (description != null)
{
var value = description.NamedArguments.First().TypedValue.ToString().Trim('"');
base.WriteAttributeString("description", value);
}
}
}
}
There are many shortcomings in this implementation. In particular, the property name and XmlElement name must be the same. Or it won't work getting the property by name: GetProperty(localName).
Use it as follows
Arm arm = ...
var xs = new XmlSerializer(typeof(Arm));
using (var writer = new DescriptionWriter("test.xml", Encoding.Unicode))
{
writer.Formatting = Formatting.Indented;
xs.Serialize(writer, arm);
}
Try following :
[XmlRoot("Arm")]
public class Arm
{
[XmlElement("ID")]
public ID id {get;set;}
[XmlElement("Dimension")]
public Dimension dimension { get; set;}
}
[XmlRoot("Dimension")]
public class Dimension
{
[XmlAttribute("description")]
public string Value { get; set; }
[XmlElement("XMin")]
public int XMin { get; set; }
[XmlElement("XMax")]
public int XMax { get; set; }
[XmlElement("YMin")]
public int YMin { get; set; }
[XmlElement("YMax")]
public int YMax { get; set; }
}
[XmlElement("ID")]
public class ID
{
[XmlAttribute("description")]
public string Value { get; set; }
[XmlText]
public int value { get; set; }
}
I'm working on a project where I have some recursive data structure and I want to create a fixture for it.
The data structure is XmlCommandElement, it has a single method ToCommand that converts XmlCommandElement to Command.
Each node on the tree can be a XmlCommandElement and/or XmlCommandPropertyElement.
Now, in order to test the behaviour of the method ToCommand I want to fetch XmlCommandElement with some arbitrary data.
I want to control the depth of the tree and the amount of instances of XmlCommandElement and/or XmlCommandPropertyElement per node.
So here is the code I'm using for the fixture:
public class XmlCommandElementFixture : ICustomization
{
private static readonly Fixture _fixture = new Fixture();
private XmlCommandElement _xmlCommandElement;
public int MaxCommandsPerDepth { get; set; }
public int MaxDepth { get; set; }
public int MaxPropertiesPerCommand { get; set; }
public XmlCommandElementFixture BuildCommandTree()
{
_xmlCommandElement = new XmlCommandElement();
var tree = new Stack<XmlCommandElementNode>();
tree.Push(new XmlCommandElementNode(0, _xmlCommandElement));
while (tree.Count > 0) {
var node = tree.Pop();
node.Command.Key = CreateRandomString();
node.Command.Properties = CreateProperties();
if (MaxDepth > node.Depth) {
var commands = new List<XmlCommandElement>();
for (var i = 0; i < MaxCommandsPerDepth; i++) {
var command = new XmlCommandElement();
tree.Push(new XmlCommandElementNode(node.Depth + 1, command));
commands.Add(command);
}
node.Command.Commands = commands.ToArray();
}
}
return this;
}
public void Customize(IFixture fixture)
{
fixture.Customize<XmlCommandElement>(c => c.FromFactory(() => _xmlCommandElement)
.OmitAutoProperties());
}
private static string CreateRandomString()
{
return _fixture.Create<Generator<string>>().First();
}
private XmlCommandPropertyElement[] CreateProperties()
{
var properties = new List<XmlCommandPropertyElement>();
for (var i = 0; i < MaxPropertiesPerCommand; i++) {
properties.Add(new XmlCommandPropertyElement {
Key = CreateRandomString(),
Value = CreateRandomString()
});
}
return properties.ToArray();
}
private struct XmlCommandElementNode
{
public XmlCommandElementNode(int depth, XmlCommandElement xmlCommandElement)
{
Depth = depth;
Command = xmlCommandElement;
}
public XmlCommandElement Command { get; }
public int Depth { get; }
}
}
And this is how I'm using it:
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
This works perfectly fine! but the issue I have with it is it isn't generic, the whole point of AutoFixture at least as far as I know is to avoid making specific fixtures.
So what I would really like to do is something like this (found it here but it doesn't work for me.):
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthThrowingRecursionBehavior(2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandElement), 3));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(XmlCommandPropertyElement), 4));
xmlCommandElement = fixture.Create<XmlCommandElement>();
Here is all the code for reference:
Interfaces:
public interface ICommandCollection : IEnumerable<ICommand>
{
ICommand this[string commandName] { get; }
void Add(ICommand command);
}
public interface ICommandPropertyCollection : IEnumerable<ICommandProperty>
{
string this[string key] { get; }
void Add(ICommandProperty property);
}
public interface ICommandProperty
{
string Key { get; }
string Value { get; }
}
public interface ICommand
{
ICommandCollection Children { get; set; }
string Key { get; }
ICommandPropertyCollection Properties { get; }
}
public interface ICommandConvertible
{
ICommand ToCommand();
}
Classes:
public sealed class CommandPropertyCollection : ICommandPropertyCollection
{
private readonly IDictionary<string, ICommandProperty> _properties;
public CommandPropertyCollection()
{
_properties = new ConcurrentDictionary<string, ICommandProperty>();
}
public string this[string key]
{
get
{
ICommandProperty property = null;
_properties.TryGetValue(key, out property);
return property.Value;
}
}
public void Add(ICommandProperty property)
{
_properties.Add(property.Key, property);
}
public IEnumerator<ICommandProperty> GetEnumerator()
{
return _properties.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public sealed class CommandProperty : ICommandProperty
{
public CommandProperty(string key, string value)
{
Key = key;
Value = value;
}
public string Key { get; }
public string Value { get; }
}
public sealed class Command : ICommand
{
public Command(string key, ICommandPropertyCollection properties)
{
Key = key;
Properties = properties;
}
public ICommandCollection Children { get; set; }
public string Key { get; }
public ICommandPropertyCollection Properties { get; }
}
public class XmlCommandPropertyElement : ICommandPropertyConvertible
{
[XmlAttribute("key")]
public string Key { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
public ICommandProperty ToCommandProperty()
{
return new CommandProperty(Key, Value);
}
}
Finally, the class I'm trying to test is as follow:
public class XmlCommandElement : ICommandConvertible
{
[XmlArray]
[XmlArrayItem("Command", typeof(XmlCommandElement))]
public XmlCommandElement[] Commands { get; set; }
[XmlAttribute("key")]
public string Key { get; set; }
[XmlArray]
[XmlArrayItem("Property", typeof(XmlCommandPropertyElement))]
public XmlCommandPropertyElement[] Properties { get; set; }
public ICommand ToCommand()
{
ICommandPropertyCollection properties = new CommandPropertyCollection();
foreach (var property in Properties) {
properties.Add(property.ToCommandProperty());
}
ICommand command = new Command(Key, properties);
return command;
}
}
The test itself looks like this:
namespace Yalla.Tests.Commands
{
using Fixtures;
using FluentAssertions;
using Ploeh.AutoFixture;
using Xbehave;
using Yalla.Commands;
using Yalla.Commands.Xml;
public class XmlCommandElementTests
{
[Scenario]
public void ConvertToCommand(XmlCommandElement xmlCommandElement, ICommand command)
{
$"Given an {nameof(XmlCommandElement)}"
.x(() =>
{
xmlCommandElement = new Fixture().Customize(new XmlCommandElementFixture {
MaxDepth = 2,
MaxCommandsPerDepth = 3,
MaxPropertiesPerCommand = 4
}.BuildCommandTree()).Create<XmlCommandElement>();
});
$"When the object is converted into {nameof(ICommand)}"
.x(() => command = xmlCommandElement.ToCommand());
"Then we need to have a root object with a key"
.x(() => command.Key.Should().NotBeNullOrEmpty());
"And 4 properties as its children"
.x(() => command.Properties.Should().HaveCount(4));
}
}
}
Thanks to Mark Seemann! the final solution looks like this:
public class RecursiveCustomization : ICustomization
{
public int MaxDepth { get; set; }
public int MaxElements { get; set; }
public void Customize(IFixture fixture)
{
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(MaxDepth));
fixture.RepeatCount = MaxElements;
}
}
And can be used like this:
xmlCommandElement = new Fixture().Customize(new RecursiveCustomization {
MaxDepth = 2,
MaxElements = 3
}).Create<XmlCommandElement>();
You can fairly easily create a small tree by changing the Fixture's recursion behaviour:
[Fact]
public void CreateSmallTree()
{
var fixture = new Fixture();
fixture.Behaviors
.OfType<ThrowingRecursionBehavior>()
.ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(recursionDepth: 2));
var xce = fixture.Create<XmlCommandElement>();
Assert.NotEmpty(xce.Commands);
}
The above test passes.
I have this:
public class Blah
{
public int id { get; set; }
public string blahh { get; set; }
}
public class Doh
{
public int id { get; set; }
public string dohh { get; set; }
public string mahh { get; set; }
}
public List<???prpClass???> Whatever(string prpClass)
where string prpClass can be "Blah" or "Doh".
I would like the List type to be class Blah or Doh based on what the string prpClass holds.
How can I achieve this?
EDIT:
public List<prpClass??> Whatever(string prpClass)
{
using (var ctx = new ApplicationDbContext())
{
if (prpClass == "Blah")
{
string queryBlah = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Blah>(queryBlah).ToList();
return result;
}
if (prpClass == "Doh")
{
string queryDoh = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Doh>(queryDoh).ToList();
return result;
}
return null
}
}
you have to have a common supertype:
public interface IHaveAnId
{
int id { get;set; }
}
public class Blah : IHaveAnId
{
public int id { get; set; }
public string blahh { get; set; }
}
public class Doh : IHaveAnId
{
public int id {get;set;}
public string dohh { get; set; }
public string mahh { get; set; }
}
then you can do:
public List<IHaveAnId> TheList = new List<IHaveAnId>();
and in some method:
TheList.Add(new Blah{id=1,blahh = "someValue"});
TheList.Add(new Doh{id =2, dohh = "someValue", mahh = "someotherValue"});
to iterate through the list:
foreach(IHaveAnId item in TheList)
{
Console.WriteLine("TheList contains an item with id {0}", item.id);
//item.id is allowed since you access the property of the class over the interface
}
or to iterate through all Blahs:
foreach(Blah item in TheList.OfType<Blah>())
{
Console.WriteLine("TheList contains a Blah with id {0} and blahh ='{1}'", item.id, item.blahh);
}
Edit:
the 2 methods and a int field holding the autovalue:
private int autoValue = 0;
public void AddBlah(string blahh)
{
TheList.Add(new Blah{id = autovalue++, blahh = blahh});
}
public void AddDoh(string dohh, string mahh)
{
TheList.Add(new Doh{id = autovalue++, dohh = dohh, mahh = mahh});
}
Another Edit
public List<object> Whatever(string prpClass)
{
using (var ctx = new ApplicationDbContext())
{
if (prpClass == "Blah")
{
string queryBlah = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Blah>(queryBlah).ToList();
return result.Cast<object>().ToList();
}
if (prpClass == "Doh")
{
string queryDoh = #"SELECT ... ";
var result = ctx.Database.SqlQuery<Doh>(queryDoh).ToList();
return result.Cast<object>.ToList();
}
return null;
}
}
in the view you then have to decide what type it is. In asp.net MVC you can use a display template and use reflection to get a good design. But then i still don't know what technology you are using.
Yet another Edit
TestClass:
public class SomeClass
{
public string Property { get; set; }
}
Repository:
public static class Repository
{
public static List<object> Whatever(string prpClass)
{
switch (prpClass)
{
case "SomeClass":
return new List<SomeClass>()
{
new SomeClass{Property = "somestring"},
new SomeClass{Property = "someOtherString"}
}.Cast<object>().ToList();
default:
return null;
}
}
}
And a controller action in mvc:
public JsonResult Test(string className)
{
return Json(Repository.Whatever("SomeClass"),JsonRequestBehavior.AllowGet);
}
then i called it with: http://localhost:56619/Home/Test?className=SomeClass
And got the result:
[{"Property":"somestring"},{"Property":"someOtherString"}]
Is this what you are trying to do?
public class Blah
{
public int id { get; set; }
public string blahh { get; set; }
}
public class Doh
{
public int id { get; set; }
public string dohh { get; set; }
public string mahh { get; set; }
}
class Program
{
public static List<T> Whatever<T>(int count) where T: new()
{
return Enumerable.Range(0, count).Select((i) => new T()).ToList();
}
static void Main(string[] args)
{
var list=Whatever<Doh>(100);
// list containts 100 of "Doh"
}
}