(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.
Related
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;
}
}
I'm wanting a class to have a property that is another class, but i want both the outside and inside classes to implement an interface, the outside interface having a property for the one on the inside.
Here's the code I've tried.
interface IMainBody
{
ISubProperty subProperty { get; set; }
}
interface ISubProperty
{
string somethingHere { get; set; }
}
class MainBody : IMainBody // Error CS0738 'MainBody' does not implement interface member 'IMainBody.subProperty'. 'MainBody.subProperty' cannot implement 'IMainBody.subProperty' because it does not have the matching return type of 'ISubProperty'.
{
public SubProperty subProperty { get; set; }
}
class SubProperty : ISubProperty
{
public string somethingHere { get; set; }
}
I know I could use a generic interface like this
interface IMainBody<T>
where T : ISubProperty
{
T subProperty { get; set; }
}
interface ISubProperty
{
string somethingHere { get; set; }
}
But I would prefer not to do this because it means the code will get very messy once there is more than one property like this.
Anyone know of any other workarounds?
class MainBody : IMainBody
{
public SubProperty subProperty { get; set; }
ISubProperty IMainBody.subProperty { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
}
I have a Json class "GetAllDevices()". My JSON response consists of an Array/List of objects, where each object has the below common properties.
public class GetAllDevices
{
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("actions")]
public Action[] Actions { get; set; }
public class Action
{
public string _id { get; set; }
public Action_Def action_def { get; set; }
}
public class Action_Def
{
public string _id { get; set; }
public string name { get; set; }
}
}
I want to create 2 generic lists containing all the above properties based on its "type".
lstfoo1 List contains all the properties(_id, name type and actions) where type="foo1". Similarly, lstfoo2 is a List which contains the above properties where type="foo2".
What I have done so far:
string strJson=getJSON();
Foo1 lstfoo1=new Foo1();
Foo2 lstfoo2=new Foo2();
List<Foo1> foo1list= lstfoo1.GetDeviceData(strJson);
List<Foo2> foo2list = lstfoo2.GetDeviceData(strJson);
public class AllFoo1: GetAllDevices
{
}
public class AllFoo2: GetAllDevices
{
}
public abstract class HomeDevices<T>
{
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1{ get; set; }
public List<AllFoo2> lstfoo2{ get; set; }
public abstract List<T> GetDeviceData(string jsonResult);
}
public class Foo1: HomeDevices<AllFoo1>
{
public Foo1()
{
type = "foo1";
}
public override List<AllFoo1> GetDeviceData(string jsonResult)
{
var lst =Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo1>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
public class Foo2: HomeDevices<AllFoo2>
{
public Foo2()
{
type = "foo2";
}
public override List<AllFoo2> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo2>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
My question is, is there an easier way to do this using abstract classes? Can I directly convert my "GetAllDevices" class into an abstract class and inherit it and deserialize into it and create a generic list?
This should help, if I understand your problem correctly. Let me know if you have questions or it doesn't work as you need. I put this together really quickly without testing.
The way the Type property is defined could be improved but I left it as you had it.
public class MyApplication
{
public void DoWork()
{
string json = getJSON();
DeviceTypeOne foo1 = new DeviceTypeOne();
DeviceTypeTwo foo2 = new DeviceTypeTwo();
IList<DeviceTypeOne> foo1Results = foo1.GetDeviceData(json); // calls GetDeviceData extension method
IList<DeviceTypeTwo> foo2Results = foo2.GetDeviceData(json); // calls GetDeviceData extension method
}
}
// implemented GetDeviceData as extension method of DeviceBase, instead of the abstract method within DeviceBase,
// it's slightly cleaner than the abstract method
public static class DeviceExtensions
{
public static IList<T> GetDeviceData<T>(this T device, string jsonResult) where T : DeviceBase
{
IEnumerable<T> deviceDataList = JsonConvert.DeserializeObject<IEnumerable<T>>(jsonResult);
IEnumerable<T> resultList = deviceDataList.Where(x => x.Type.Equals(typeof(T).Name));
return resultList.ToList();
}
}
// abstract base class only used to house common properties and control Type assignment
public abstract class DeviceBase : IDeviceData
{
protected DeviceBase(string type)
{
if(string.IsNullOrEmpty(type)) { throw new ArgumentNullException(nameof(type));}
Type = type; // type's value can only be set by classes that inherit and must be set at construction time
}
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; private set;}
[JsonProperty("actions")]
public DeviceAction[] Actions { get; set; }
}
public class DeviceTypeOne : DeviceBase
{
public DeviceTypeOne() : base(nameof(DeviceTypeOne))
{
}
}
public class DeviceTypeTwo : DeviceBase
{
public DeviceTypeTwo() : base(nameof(DeviceTypeTwo))
{
}
}
// implemented GetAllDevices class as IDeviceData interface
public interface IDeviceData
{
string Id { get; set; }
string Name { get; set; }
string Type { get; }
DeviceAction[] Actions { get; set; }
}
// renamed and relocated class Action to DeviceAction
public class DeviceAction
{
public string Id { get; set; }
public DeviceActionDefinition DeviceActionDefinition { get; set; }
}
// renamed and relocated Action_Def to DeviceActionDefinition
public class DeviceActionDefinition
{
public string Id { get; set; }
public string Name { get; set; }
}
It should be simple enough to move the implementation of method GetDeviceData() to the base class.
For this to work, you will need to add a constraint on T so the compiler knows a bit more about the base type. You will also need to implement a constructor to populate the concrete type's type string you use around. This is a necessary measure to ensure the value is always populated as it is used for comparison in the method in question:
public abstract class HomeDevices<T> where T: GetAllDevices
{
public HomeDevices(string concreteType)
{
type = concreteType;
}
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1 { get; set; }
public List<AllFoo2> lstfoo2 { get; set; }
//This method is now generic and works for both.
public List<T> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
I hope that helps.
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!";
}
The case is very simple, I have this interface
public interface IHasNext
{
IHasNext NextItem { get; set; }
}
and then I attempt to implement it like so:
public class Item : IHasNext
{
public int Id { get; set; }
Item NextItem { get; set; }
}
but this won't work because the property NextItem of the implementation is not of the same type (even if the type implements the interface). So could someone kindly explain me the reason for this not working, when you can quite liberally swap types for interfaces they implement even as type parameters (at least on IEnumerable and IQueryable).
Consider this code:
public class BadItem : IHasNext
{
public IHasNext { get; set; }
}
Now:
IHasNext item = new Item();
item.NextItem = new BadItem();
That's perfectly valid... but what would you expect it to do on the Item class? Its NextItem property is of type Item, so it doesn't know what to do with a BadItem...
Basically, doing this is unsafe.
You may want to make your interface generic:
public interface IHasNext<T> where T : IHasNext<T>
{
T NextItem { get; set; }
}
public class Item : IHasNext<Item>
{
public int Id { get; set; }
IHasNext<Item> NextItem { get; set; }
}
The interface states that the property must be of type IHasNext, your code should be:
public class Item : IHasNext
{
public int Id { get; set; }
IHasNext NextItem { get; set; }
}
Why aren't you implementing it as:
public class Item : IHasNext
{
public int Id { get; set; }
IHasNext NextItem { get; set; }
}
? This interface could be on any class that implements IHasNext.
But better still is to make it generic
public interface IHasNext<T>
{
T NextItem { get; set; }
}
public class Item : IHasNext<Item>
{
public int Id { get; set; }
Item NextItem { get; set; }
}