I'm fighting with some classes or better objects taht are nested in a "main object".
Example:
public class Parent
{
public string MothersName { get; set; }
public Child child = new Child(){ ChildsName = "Child1"; }
}
public class Child
{
public string ChildsName{ get; set; }
.... Parent MothersName = "LovelyOne";
}
So is there any way to change the mothers name from the child-object?
The child needs to have a reference to the parent class:
public class Parent
{
public string MothersName { get; set; }
public Child child;
public Parent()
{
child = new Child("Child1", this);
}
}
public class Child
{
public string ChildsName { get; set; }
public Parent Parent { get; }
public Child(string childsName, Parent parent)
{
this.ChildsName = childsName;
this.Parent = parent;
}
}
myChild.Parent.MothersName = "LovelyOne"; works now inside of Child.
Related
This is possible in PG:
public class Parent
{
[Column(TypeName = "jsonb")]
//Mode 1: a column in the table
public Child[] Children { get; set; }
}
public class Child
{
//Mode 2: a virtual column only existing in JSON
public GrandChild[] GrandChildren { get; set; }
}
public class GrandChild
{
}
My question if there is a way to use other CLR types inline, instead of arrays, such as List<T>, HashSet<T> or even just IList<T> or ICollection<T>, to enable easy access and to avoid recreation of the collection each time we want to make a change, or to avoid defining a bunch of other proxy properties.
I tried setting HasConversion to array but it didn't work.
This works "automatically" if you enable the type plugins in Npgsql.Json.NET:
NpgsqlConnection.GlobalTypeMapper.UseJsonNet();
using (var context = new MyContext(options.Options))
{
var parent = new Parent()
{
Children = {
new Child() {
GrandChildren = {
new GrandChild() { Name = "A" },
new GrandChild() { Name = "B" }
}
}
}
};
context.Add(parent);
context.SaveChanges();
foreach(var p in context.Parents.ToList()) {
// This is just to print the whole object. You don't have to touch JSON.NET
// yourself here, Npgsql will convert to/from .net types at 'the edges'.
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(p));
}
}
// Using these definitions
class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options)
: base(options)
{ }
public DbSet<Parent> Parents { get; set; }
}
public class Parent
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column(TypeName = "jsonb")]
public List<Child> Children { get; set; } = new List<Child>();
}
public class Child
{
public List<GrandChild> GrandChildren { get; set; } = new List<GrandChild>();
}
public class GrandChild
{
public string Name { get; set; }
}
public sealed class ParentSource
{
public string Name { get; }
public List<ChildSource> Children { get; }
public ParentSource(string name)
{
Name = name;
Children = new List<ChildSource>();
}
}
public sealed class ChildSource
{
public string Name { get; }
public ChildSource(string name)
{
Name = name;
}
}
public sealed class ParentDestination
{
public string Name { get; }
public List<ChildDestination> Children { get; }
public ParentDestination(string name)
{
Name = name;
Children = new List<ChildDestination>();
}
}
public sealed class ChildDestination
{
public string Name { get; }
public ChildDestination(string name)
{
Name = name;
}
}
To my understanding, all I need are the following mappings:
CreateMap<ParentSource, ParentDestination>();
CreateMap<ChildSource, ChildDestination>();
Call the mapping:
var parentSource = new ParentSource("parent");
var childSource = new ChildSource("child");
parentSource.Children.Add(childSource);
var parentDestination = mapper.Map<ParentSource, ParentDestination>(parentSource);
The child collection of the destination parent doesn't contain any members unless I add a public setter to the Children property. How can I make this work without a public setter?
This small test here:
[TestClass]
public class TreeXTests
{
[TestMethod]
public void ShouldCreateSmallTree()
{
// Arrange
var fixture = new Fixture();
fixture.Behaviors.Add(new OmitOnRecursionBehavior(3));
fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
// Act
var em = fixture.Create<TreeX>();
// Assert
em.Should().NotBeNull();
}
}
Works fine when I have classes defined like this:
class TreeX
{
public MetaX MetaX { get; set; }
public IReadOnlyList<TreeX> Children { get; set; }
public TreeX OtherTreePointer { get; set; }
}
class MetaX
{
public int A { get; set; }
}
But when I add constructors and remove public setters:
class TreeX
{
public TreeX(MetaX metaX, IReadOnlyList<TreeX> children, TreeX otherTreePointer = null)
{
MetaX = metaX;
Children = children;
OtherTreePointer = otherTreePointer;
}
public MetaX MetaX { get; }
public IReadOnlyList<TreeX> Children { get; }
public TreeX OtherTreePointer { get; }
}
class MetaX
{
public MetaX(int a)
{
A = a;
}
public int A { get; }
}
It fails with the following error:
AutoFixture.ObjectCreationExceptionWithPath: AutoFixture was unable to create an instance from TreeX, most likely because it has no public constructor, is an abstract or non-public type.
Which is not really helpful.
Also I found that if I remove OtherTreePointer from TreeX then it works again:
class TreeX
{
public TreeX(MetaX metaX, IReadOnlyList<TreeX> children)
{
MetaX = metaX;
Children = children;
}
public MetaX MetaX { get; }
public IReadOnlyList<TreeX> Children { get; }
}
...but I really need OtherTreePointer. I don't want to redesign my classes and immutability is a must.
I'm not sure whether this is an issue with the library, but if not then how can I make it work?
Thanks.
I have a JSON structure (including POCO classes) with child-objects arrays like this:
"Object": [
{
"Name": "TestA",
"ChildObjects": [
{
"Name": "TestB"
"ChildObjects": [
{
"Name": "TestC"
...
}
]
}
]
When deserializing, I would like to keep a reference to the parent
object I've just created.
But I must get this reference before populating the child-object.(On the moment that I populate the child-object I must have the parent-object structure/reference accessible).
I've tried using a custom JsonConverter, but
I could not find a way to store or retrieve this relationship.
Rather than defining this as a serialization problem (how to serialize and deserialize a back-reference to a parent), it might make sense to define this as a class design problem, namely
Given a hierarchy of parents and children, how to ensure that child back-references to parents are automatically set correctly when adding them to their parents?
Once the problem is defined in this way and solved, correctness should be assured both during deserialization and during programmatic data creation, since the parent back-reference would never need to be serialized or deserialized.
One way to accomplish this would be to define a custom subclass of Collection<T> that automatically sets and clears parent back references.
First, define the following interface and collection:
public interface IHasParent<TParent> where TParent : class
{
TParent Parent { get; }
void OnParentChanging(TParent newParent);
}
public class ChildCollection<TParent, TChild> : Collection<TChild>
where TChild : IHasParent<TParent>
where TParent : class
{
readonly TParent parent;
public ChildCollection(TParent parent)
{
this.parent = parent;
}
protected override void ClearItems()
{
foreach (var item in this)
{
if (item != null)
item.OnParentChanging(null);
}
base.ClearItems();
}
protected override void InsertItem(int index, TChild item)
{
if (item != null)
item.OnParentChanging(parent);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
var item = this[index];
if (item != null)
item.OnParentChanging(null);
base.RemoveItem(index);
}
protected override void SetItem(int index, TChild item)
{
var oldItem = this[index];
if (oldItem != null)
oldItem.OnParentChanging(null);
if (item != null)
item.OnParentChanging(parent);
base.SetItem(index, item);
}
}
Then define your MyObject and RootObject types as follows:
public class MyObject : IHasParent<MyObject>
{
readonly ChildCollection<MyObject, MyObject> childObjects;
public MyObject() { this.childObjects = new ChildCollection<MyObject, MyObject>(this); }
public string Name { get; set; }
public IList<MyObject> ChildObjects { get { return childObjects; } }
#region IHasParent<MyObject> Members
[JsonIgnore]
public MyObject Parent { get; private set; }
public void OnParentChanging(MyObject newParent)
{
Parent = newParent;
}
#endregion
// Added to suppress serialization of empty ChildObjects collections to JSON.
public bool ShouldSerializeChildObjects() { return childObjects.Count > 0; }
}
public class RootObject
{
public RootObject() { this.Object = new List<MyObject>(); }
public List<MyObject> Object { get; set; }
}
Notes:
The collection IList<MyObject> ChildObjects in MyObject is get-only. Json.NET (and XmlSerializer for that matter) can successfully deserialize a get-only, pre-allocated collection.
The method ShouldSerializeChildObjects() is optional and prevents serialization of empty ChildObjects [] array values.
Since ObservableCollection<T> is itself a subclass of Collection<T>, you could chose it as the base class for ChildCollection<TParent, TChild> if you require notifications when items are added or removed.
The Parent property is marked with [JsonIgnore] to prevent its serialization.
Sample fiddle including some basic unit tests.
For clearer understanding dbc's answer let me simplify it.
Let's take example of setting parent for RootObject's item called MyObject:
{
"Object":[
{
"Name": "TestA"
}
]
}
Define collection:
public class Items : Collection<MyObject>
{
private RootObject Owner;
public Items(RootObject owner)
{
Owner = owner;
}
protected override void InsertItem(int index, MyObject item)
{
item.Parent = Owner;
base.InsertItem(index, item);
}
}
Define MyObject and RootObject:
public class MyObject
{
[JsonIgnore]
public RootObject Parent { get; set; }
public string Name { get; set; }
}
public class RootObject
{
public RootObject() { ChildObjects = new Items(this); }
public Items ChildObjects { get; }
}
You needn't JsonConverter.
You can create POCO classes that represent your json, as given below:
public class OstacolisRuntime
{
public int CodiceOstacolo { get; set; }
public int TipoOstacolo { get; set; }
public int Tipologia { get; set; }
public string Nome { get; set; }
public double PosizioneX { get; set; }
public double PosizioneY { get; set; }
public double PosizioneZ { get; set; }
public double AngoloX { get; set; }
public double AngoloY { get; set; }
public double AngoloZ { get; set; }
public double ScalaX { get; set; }
public double ScalaY { get; set; }
public double ScalaZ { get; set; }
public List<SubOggetto> SubOggettos { get; set; } //sub
}
public class SubOggetto
{
public string Immagine { get; set; }
public int Tipologia { get; set; }
public string Nome { get; set; }
public double PosizioneX { get; set; }
public double PosizioneY { get; set; }
public double PosizioneZ { get; set; }
public double AngoloX { get; set; }
public double AngoloY { get; set; }
public double AngoloZ { get; set; }
public double ScalaX { get; set; }
public double ScalaY { get; set; }
public double ScalaZ { get; set; }
public List<SubOggetto> SubOggettos { get; set; } //recursive relashioship
}
public class RootObject
{
public List<OstacolisRuntime> OstacolisRuntime { get; set; }
}
Deserialize you json:
var o= JsonConvert.DeserializeObject<RootObject>(json);
You can check complete source code
Let's say I've got a class:
public class Parent
{
public string Name { get; set; }
public string City { get; set; }
}
and in some function I'm getting the list of objects type Parent, next I'd like to extend those objects with new field with some value, so I'm declaring an extended class like this:
public class Child : Parent
{
public Child(Parent parent)
{
Name = parent.Name;
City = parent.City;
}
public int Age { get; set; }
}
and call the costructor for each extended object. Is there a better way to do that? What if there will be multiple properties in Parent? Maybe there is some more elegant way to achieve that?
I think maybe you're looking for a copy-constructor pattern. Each level defines a protected constructor which copies the relevant properties:
public class Parent
{
public string Name { get; set; }
public string City { get; set; }
//normal constructor
public Parent()
{
}
protected Parent(Parent copy)
{
this.Name = copy.Name;
this.City = copy.City;
}
}
The Child would inherit from Parent, pass it down through to the copy-constructor, then append its new values as desired:
public class Child : Parent
{
public string NewInfo { get; set; }
public Child(Parent copy)
: base(copy)
{
}
}
Usage might look like:
Parent parent = new Parent() { Name = "Name", City = "StackOverflow"};
Child child = new Child(parent) { NewInfo = "Something new!" };
Console.WriteLine(child.Name); //Name
Console.WriteLine(child.City); //StackOverflow
Console.WriteLine(child.NewInfo); //Something new!
The benefit from this is that you can have multiple levels of inheritance with each level managing their own properties.
EDIT: Given your most recent comment:
The motivation to this question is a situation in where I'm getting a
list of objects with data, and want to show this data but with some
additional fields, without touching the base class.
Perhaps the better method then is to wrap the base class:
public class Child
{
private readonly Parent WrappedParent;
public string NewInfo { get; set; }
public string Name
{
get { return WrappedParent.Name; }
set { WrappedParent.Name = value; }
}
public string City
{
get { return WrappedParent.City; }
set { WrappedParent.City = value; }
}
public Child(Parent wrappedParent)
{
this.WrappedParent = wrappedParent;
}
}
Downside is you have to redeclare each property, and you are no longer inheriting (cannot be considered a) "Parent", but then you are definitly "not touching" the base class anymore. Could move the "Parent" properties into an IParent interface if that's better for you, but doing so again is "touching" the base class as you'll have to add the IParent interface declaration to its class definition.
Not sure if I got you wrong, but this could be a more standar solution
public class Parent
{
public Parent(string name, string city)
{
Name = name;
City = city;
}
public string Name { get; set; }
public string City { get; set; }
}
public class Child : Parent
{
public Child(string name, string city, int age) : base(name, city)
{
Age = age;
}
public int Age { get; set; }
}
You can do this
public class Parent
{
public string Name { get; set; }
public string City { get; set; }
public Parent(string name, string city)
{
this.Name = name;
this.City = city;
}
public Parent():this(string.Empty, string.Empty)
{
}
}
public class Child : Parent
{
public Child(Parent parent, int age):base(parent.Name, parent.City)
{
this.Age = age;
}
public int Age { get; set; }
}