immutable data with circular dependencies - c#

I have a bunch of classes which are supposed to represent data. These classes are nested, so they form a tree (or, in simple cases, a chain). Since the data should just be created once and then only read, I use classes with init-only properties:
public class Foo { public Bar Bar { get; init; } }
public class Bar { public Baz Baz { get; init; } }
public class Baz { public int Value { get; init; } }
In order to navigate such a tree/chain not just from top to bottom, I need an Owner (or Parent) property for each class. So let's assume I have it like this:
public interface IData { }
public class Data<OwnerType> : IData where OwnerType : IData
{ public OwnerType Owner { get; init; } }
public class Foo : IData { public Bar Bar { get; init; } }
public class Bar : Data<Foo> { public Baz Baz { get; init; } }
public class Baz : Data<Bar> { public int Value { get; init; } }
But now I have a problem with circular dependencies: In order to create a non-empty Foo, I must set its Foo.Bar property during construction. But that Bar object needs a Foo object as Bar.Owner property set during construction, which cannot be the Foo currently in creation (because it hasn't been created yet), although that's the one it should be.
var foo = new Foo { Bar = new Bar { Owner = foo, ... } }; // this does not work but this is what I want
How can I solve this problem?
I could make the Owner property have a (private) setter. But I don't like this because private doesn't say this can be set only once.

"A" solution would be to make the setter of Data public, and set it in the class constructor.
Note: IMHO Data is a bad name, So I renamed it:
public interface IsOwner { }
public class OwnedBy<OwnerType> where OwnerType : IsOwner
{ public OwnerType Owner { get; set; } }
public class Foo : IsOwner
{
public Bar _bar { get; init; }
public Foo(Bar bar)
{
bar.Owner = this;
_bar = bar;
}
}
public class Bar : OwnedBy<Foo>, IsOwner
{
public Baz _baz { get; init; }
public Bar(Baz baz)
{
baz.Owner = this;
_baz = baz;
}
}
public class Baz : OwnedBy<Bar>
{
public int _value { get; init; }
public Baz(int value)
{
_value = value;
}
}
static class Program
{
static void Main()
{
var foo = new Foo(new Bar(new Baz(1)));
}
}
edit: I missed the set-once item in your question.
You can indeed back the Owner up with a private field, ensuring it's set once
public class OwnedBy<OwnerType> where OwnerType : IsOwner
{
private OwnerType owner;
public OwnerType Owner { get => owner; set => owner ??= value; }
}
Or even throw an exception is set twice.
public OwnerType Owner
{
get => owner; set {
if (owner is not null) throw new InvalidOperationException(
$"{nameof(Owner)} can only be set once");
owner = value;
}
}

Related

Mapster ConstructUsing with class with multiple ctor problem (bug?)

I have a problem with Mapster. There is some classes
public class DtoClass
{
public string Name { get; set; }
public ParamValueDto Value { get; set; }
}
public class ParamValueDto
{
public int Value { get; set; }
}
public class TargetClass
{
public string Name { get; set; }
public object Value { get; set; }
public TargetClass(string name, object value)
{
Name = name;
Value = value;
}
}
public class TargetParamValue
{
public int Value { get; set; }
public TargetParamValue(int value)
{
Value = value;
}
}
Config:
config.ForType<DtoClass, TargetClass>()
.MapToConstructor(true)
.ConstructUsing(x => new TargetClass(x.Name, new TargetParamValue(x.Value)));
Everything is fine, the objects are mapped as expected, but if you add one more constructor to the TargetClass
public class TargetClass
{
public string Name { get; set; }
public object Value { get; set; }
public TargetClass(string name, object value)
{
Name = name;
Value = value;
}
public TargetClass(Foo foo) //Where Foo is any class
{
Name = "fsdf";
Value = new ParamValueDto();
}
}
In the final result, Value will not contain TargetParamValue as expected, but ParamValueDto, as if result ConstructUsing is ignored (but called) or overwritten. The constructor is called correctly - and TargetParamValue comes to value, but the final result will have an incorrect param (with ParamValueDto in Value).
(New ctor - not called)

Hide setter of property in nested classes in C# [duplicate]

I have the nub of the code like this:
public class OuterClass
{
public static InnerClass GetInnerClass()
{
return new InnerClass() { MyProperty = 1 };
}
public class InnerClass
{
public int MyProperty { get; set; }
}
}
what is the solution to property named MyProperty just be settable from the InnerClass and the OuterClass, and out of these scopes, MyProperty just be readonly
There is no protection level for that. internal is the tightest you can use, which is limited to files in the same assembly. If you cannot make it a constructor parameter as has been proposed, you could use an interface:
public class OuterClass
{
public static InnerClass GetInnerClass()
{
return new InnerClassImpl() { MyProperty = 1 };
}
public interface InnerClass
{
int MyProperty { get; }
}
private class InnerClassImpl : InnerClass
{
public int MyProperty { get; set; }
}
}
I'm afraid there is no access modifier which allows that. You can create IInnerClass interface and make the property readonly within interface declaration:
public class OuterClass
{
public static IInnerClass GetInnerClass()
{
return new InnerClass() { MyProperty = 1 };
}
public interface IInnerClass
{
int MyProperty { get; }
}
private class InnerClass : IInnerClass
{
public int MyProperty { get; set; }
}
}

removing an item from an interface based collection will not work

(FYI, Foo and Bar are Entity Framework POCO entity classes)
I would like to use this interface:
public interface IFoo
{
int Id { get; set; }
string Name { get; set; }
ICollection<IBar> IBars{ get; set; } //association with another entity
}
My implementation is as follows:
public class Foo : IFoo
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Bar> Bars{ get; set; }
//Interface implementation
public ICollection<IBar> IBars
{
get
{
return Bars.Cast<IBar>().ToList();
//or return new List<ICardInquiry>(CardsInquiries);
}
set
{
if (value is ICollection<IBar>)
Bars= ((ICollection<IBar>)value).Cast<Bar>().ToList();
else
throw new NotImplementedException();
}
}
}
This implementation prevents me to remove an element from the collection:
IFoo iFoo = MyIFooFactory.CreateIFoo();
IBar iBar = iFooIBars.First();
iFoo.IBars.Remove(iBar);
This will NOT remove the element! I do understand why. The reason is my interface collection getter, which is again as follows:
public ICollection<IBar> IBars
{
get
{
return Bars.Cast<IBar>().ToList();
//or return new List<ICardInquiry>(CardsInquiries);
}
...
}
IBars returns a new list so the element is removed from the returned list and not from the original collection (Bars).
How can I get out of this situation? I really don't want IFoo to know about Bar and to only manimpulate IBar.

How to build a class with "generic" type and instancing it to the derived one?

I have this situation
public class CustomClass
{
public string stringTest { get; set; }
public int numberTest { get; set; }
public (xy) foo { get; set; }
}
Which will be my main class, then:
public class Base
{
public string somePropery { get; set; }
}
public class Derived : Base
{
public string someOtherProperty { get; set;}
}
public class Derived2 : Base
{
public string someHappyProperty { get; set;}
}
I would like to do this:
CustomClass test = new CustomClass()
{
foo = new Derived()
}
test.foo.someOtherProperty = "Wow!";
or
CustomClass test = new CustomClass()
{
foo = new Derived2()
}
test.foo.someHappyProperty = "Wow!";
Obviously I can't set foo's type as Base and I would prefer to avoid the use of the dynamic type, what is the correct way to handle this?
Make CustomClass generic:
public class CustomClass<T>
where T : Base
{
public string stringTest { get; set; }
public int numberTest { get; set; }
public T foo { get; set; }
}
You can now write:
CustomClass<Derived> test = new CustomClass<Derived>()
{
foo = new Derived()
};
test.foo.someOtherProperty = "Wow!";
Obviously I can't set foo's type as Base
Why not?
If you know it's going to be a Derived, set its type to Derived. If you don't, set it to Base. If you later want to check to see if it is a Derived and set Derived-specific members on it, you can use the is keyword:
if (test.foo is Derived)
{
((Derived) test.foo).someOtherProperty = "Wow!";
}

Adding additional properties without having to overwrite base properties

I have a number of classes deriving from an abstract base class. The concrete classes are stored in a container by references to base class. The concrete classes have many properties which are used to bind to pages in a FixedDocument.
I want to add aditional properties to the concrete classes at runtime which will also bind to the FixedDocument pages. I looked into the decorator pattern but it seems i have to override all the concrete class properties in the decorator class for them to be visible. Is there a way of adding a wrapper that is derived from the concrete class that inherits the values of the base properties as follows:
class BaseClass
{
public string Name { get; set; }
}
class ConcreteClass : BaseClass
{
public int MyProperty { get; set; }
}
class ConcreteClassWrapper : ConcreteClass
{
public int AdditionalProperty { get; set; }
public ConcreteClassWrapper(ConcreteClass cc)
{
base = cc;
}
}
private static void RunTime()
{
List<BaseClass> list = new List<BaseClass>();
ConcreteClass cc = new ConcreteClass()
{
Name = "Original",
MyProperty = 5
};
list.Add(cc);
cc = new ConcreteClassWrapper(cc)
{
AdditionalProperty = 10
};
}
Obviously i cant just set 'base = cc'. Is there anyway to achieve this?
Can you modify ConcreteClass so that it has an additional constructor:
class ConcreteClass : BaseClass
{
public int MyProperty { get; set; }
public ConcreteClass(ConcreteClass copy)
{
this.MyProperty = copy.MyProperty;
}
}
class ConcreteClassWrapper : ConcreteClass
{
public int AdditionalProperty { get; set; }
public ConcreteClassWrapper(ConcreteClass cc)
base(cc)
{
}
}
You can imagine the wrapper class to be defined like this
class ConcreteClassWrapper : ConcreteClass
{
public string Name { get; set; } // Inherited from BaseClass
public int MyProperty { get; set; } // Inherited from ConcreteClass
public int AdditionalProperty { get; set; }
}
It contains all the members declared in the all the base classes, since it inherits them.
You can create a new instance like this (assuming that you have a default constructor)
var wrapper = new ConcreteClassWrapper {
Name = "xy",
MyProperty = 5,
AdditionalProperty = 7
};
However, if you want the wrapper to be a true wrapper, do not inherit from the base class
class ConcreteClassWrapper
{
private ConcreteClass _cc;
public ConcreteClassWrapper(ConcreteClass cc)
{
_cc = cc;
}
public string Name { get { return _cc.Name; } set { _cc.Name = value; } }
public string MyProperty{ get { return _cc.MyProperty; } set { _cc.MyProperty = value; } }
public int AdditionalProperty { get; set; }
}

Categories

Resources