How to create my own generic list class? - c#

I have this :
public class CChainElement
{
public CChainElement m_Prev, m_Next;
}
public class CChainList : IEnumerable
{
public CChainElement m_First;
internal void Add(CChainElement Element)
{
if (m_First != null)
m_First.m_Prev = Element;
Element.m_Next = m_First;
m_First = Element;
}
}
public class CEntity : CChainElement
{
}
public class CItem : CEntity
{
}
public class CTest
{
void Test()
{
CChainList AllItem = new CChainList();
CItem Item = new CItem();
AllItem.Add(Item);
CItem FirstItem = AllItem.m_First as CItem;
CItem SecondItem = FirstItem.m_Next as CItem;
}
}
And I'd like to switch to something like this :
public class CChainElement<T> where T : CChainElement<T>
{
public T m_Prev, m_Next;
}
public class CChainList<T> : IEnumerable where T : CChainElement<T>
{
public T m_First;
internal void Add(T Element)
{
if (m_First != null)
m_First.m_Prev = Element;
Element.m_Next = m_First;
m_First = Element;
}
}
public class CEntity : CChainElement<CEntity>
{
}
public class CItem : CEntity
{
}
public class CTest
{
void Test()
{
CChainList<CItem> AllItem = new CChainList<CItem>();
CItem Item = new CItem();
AllItem.Add(Item);
CItem FirstItem = AllItem.m_First; // Yeepee, no more "as CItem" ..! ;-)
CItem SecondItem = FirstItem.m_Next;
}
}
And I get the error that CItem can't be converted to CChainElement<CItem> .
So my question is : is there anyway to constrain public class CChainElement<T> so it'll take CItem graciously, even if it doesn't inherit directly from CChainElement ?
My goal is obviously that all classes inherited from CChainElement<T> being able to be listed with my generic list class, while avoiding the explicit cast.
Thanks in advance for any help !
EDIT: in my full project, CEntity is used for many different things as an abstraction class (ie: I can manipulate Monsters in a similar way than Items through it), so it can't be changed to be a generic CEntity<T> .

CChainElement should not be generic. The only thing that should turn to a generic is CChainList.
public class CChainElement
{
public CChainElement m_Prev, m_Next;
}
public class CChainList<T> : IEnumerable
where T : CChainElement
{
public T m_First;
internal void Add(T Element)
{
if (m_First != null)
m_First.m_Prev = Element;
Element.m_Next = m_First;
m_First = Element;
}
}
public class CEntity : CChainElement
{
}
public class CItem : CEntity
{
}
public class CTest
{
void Test()
{
CChainList<CItem> AllItem = new CChainList<CItem>();
CItem Item = new CItem();
AllItem.Add(Item);
CItem FirstItem = AllItem.m_First;
CItem SecondItem = FirstItem.m_Next;
}
}

Well, this is a fun little problem. You need to make these changes:
public class CEntity<T> : CChainElement<T> where T : CChainElement<T> { ... }
public class CItem : CEntity<CItem> { ... }
Then this will work the way you want:
var allItems = new CChainList<CItem> { new CItem(), new CItem() };
// Both of these are now of type Item.
var firstItem = allItems.m_First;
var secondItem = firstItem.m_Next;
Another option is to make ChainElement a generic interface:
public interface IChainElement<T> where T : IChainElement<T>
{
T Previous { get; set; }
T Next { get; set; }
}
But then you will have to explicitly add the properties to each class you want to put in the list:
public class Entity { }
public class Item : Entity, IChainElement<Item>
{
public Item Previous { get; set; }
public Item Next { get; set; }
}
Either way you end up needing to modify all the classes you want to use in your list.
As an aside, you might want to use a better set of naming conventions. Prefacing all your class names with C, naming parameters and locals with InitialCapitals and public fields starting with m_ make your code pretty hard to read! I would recommend something like this:
public class ChainElement<T> where T : ChainElement<T>
{
public T Previous { get; set; }
public T Next { get; set; }
}
public class ChainList<T> : IEnumerable where T : ChainElement<T>
{
public T First { get; private set; }
public void Add(T element)
{
if (First != null)
First.Previous = element;
element.Next = First;
First = element;
}
public IEnumerator GetEnumerator() { throw new NotImplementedException(); }
}
public class Entity<T> : ChainElement<T> where T : ChainElement<T> { }
public class Item : Entity<Item> { }

Related

How to handle/cast a recursive generic classes inheritance?

I will plot an example to illustrate my behind the scene issues.
Let say I have this base generic class :
public abstract class ContainerBase<T>
{
Guid Id {get; init;}
IList<T> Items {get; set;}
bool IsLeaf {get; set;} = false;
/// omitted constructors and so
}
Then I have a whole bunch (undefined number) of concrete Container class that have another ContainerBase<...> as the T type argument :
public class RootContainer : ContainerBase<ChildContainer1>
{...}
public class ChildContainer1: ContainerBase<ChildContainer2>
{...}
public class ChildContainer2: ContainerBase<ChildContainer3>
{...}
...
public class ChildContainerNminus1: ContainerBase<ChildContainerN>
{...}
public class ChildContainerN: ContainerBase<int> // the recursion end here.
{
...
IsLeaf = true;
}
Now let say I have an AddContainer method from an Utility class and have access to the RootContainer object (a singleton for example) that is fully populated of recursive sub containers.
public static class ContainerUtility
{
// What is the Type of the recursive currentContainer ?
public static ContainerBase<T> FindContainer<T>(Guid id, ContainerBase<?> currentContainer)
{
if(currentContainer.Id == id)
return currentContainer;
if(currentContainer.IsLeaf) return default;
foreach(var item in currentContainer.Items)
{
var potential = FindContainer(id, item);
if(potential != default) return potential;
}
return default;
}
public static bool AddContainer<T>(ContainerBase<T> container, Guid parentId)
{
// potential should be of container's parent type (ContainerBase<"T-1">)
// but how to "bybass" an expected type parameter as I cannot know it ?
var potential = FindContainer<?>(parentId, RootContainer.Instance)
if(potential != default && potential is ContainerBase<?>)
{
potential.Items.Add(container)
return true;
}
return false;
}
}
You see, my issue is that I have a base type ContainerBase that is convenient for recursive search as all subClasses allow access to Items list to pursue recursion.
But at each step of the recursion it is a different actual type of ContainerBase<?>.
So I cannot perform cast on the method argument.
maybe use a top level interface that expose a List<object> Items ? Not sure that will end up good.
Bellow was my intermediate mid-solution on my issue.
I'll keep it for the record or erase it if you request it to clarify this response.
Ok I get something more interesting now. I would like to have your criticism of this solution I end up with :
Mainly I abstracted a way higher with a non generic interface to avoid my issue described in OP.
The Interface
public interface IContainer
{
int TAG { get; init; } // usefull for logging purpose
string Name { get; }
Guid Id { get; init; }
public bool IsLeaf { get;}
IList<IContainer>? GetContainers();
void SetContainers(List<IContainer> value);
}
The base class
public abstract class ContainerBase<T> : IContainer where T : IContainer
{
public int TAG { get; init; }
public Guid Id { get; init; }
private IList<IContainer>? _containers = new List<IContainer>();
public IList<T> Items { get; set; } = new List<T>();
public bool IsLeaf => this.GetType() == typeof(T);
public string Name => this.GetType().Name + "_" + TAG;
public ContainerBase(Guid id)
{
TAG = ContainerUtils.ContainerCount++;
Id=id;
}
public ContainerBase()
{
TAG = ContainerUtils.ContainerCount++;
Id = Guid.NewGuid();
}
public IList<IContainer>? GetContainers()
{
if(Items == null) return null;
if(_containers == null || !_containers.Any())
_containers = Items.Where(x => x!=null).Select(x => (IContainer)x!).ToList();
return _containers;
}
public void SetContainers(List<IContainer> value)
{
Items = new List<T>();
foreach(var item in value)
{
if (item is T)
Items.Add((T)item);
}
}
}
The concrete classes
internal class RootContainer : ContainerBase<Child1Container>
{
public RootContainer(Guid id) : base(id)
{
}
public RootContainer() : base()
{
}
}
The intermediate containers are the same only class name change (X = 1 to 3 in my test case)
internal class ChildXContainer : ContainerBase<ChildX+1Container>
{
public ChildXContainer(Guid id) : base(id)
{
}
public ChildXContainer() : base()
{
}
}
The leaf class (end point of my chained containers classes recursion).
internal class LeafContainer : ContainerBase<LeafContainer>
{
public int IntItem { get; set; }
public LeafContainer() : base()
{
}
public LeafContainer(Guid id) : base(id)
{
}
}
Do note I'm using a trick to detect if a ContainerBase<T> concrete implementation is a leaf or not :
If such classes are leaves then they have to derive from ContainerBase<> of themselves.
Kind like the CRTP syntax, but without its meaning.
So I'm not fully satisfied of this trick, but better than my previous attempt so far.
The Utility class
internal static class ContainerUtils
{
public static int ContainerCount = 0;
public static Guid IdToSearch {
get
{
if(!AllIds.Any())
return Guid.Empty;
return AllIds[new Random().Next(AllIds.Count - 1)];
}
//set { IdToSearch = value; }
}
public static List<Guid> AllIds { get; set; } = new();
private static RootContainer _root = BuildContainers();
public static RootContainer Root => _root;
private static RootContainer BuildContainers()
{
LeafContainer Leaf = new LeafContainer();
Child3Container Child3 = new Child3Container();
Child2Container Child2 = new Child2Container();
Child1Container Child1 = new Child1Container();
RootContainer Root = new RootContainer();
Root.Items.Add(Child1);
Child1.Items.Add(Child2);
Child2.Items.Add(Child3);
Child3.Items.Add(Leaf);
Leaf.IntItem = 12;
AllIds.Add(Root.Id);
AllIds.Add(Child1.Id);
AllIds.Add(Child2.Id);
AllIds.Add(Child3.Id);
AllIds.Add(Leaf.Id);
return Root;
}
private static IContainer? _GetSubContainer(this IContainer container, int index)
=> (container == null ||
container.GetContainers() == null ||
index >= container.GetContainers()!.Count) ? null : container.GetContainers()![index];
public static string ContainersToString()
=> ContainersToString(Root);
public static string ContainersToString(IContainer? fromContainer)
{
if (fromContainer == null) return string.Empty;
int i = 0;
string tab = " ";
string res = "";
while(fromContainer != null)
{
res += tab.Repeat(i) + "+" + fromContainer.Name??"NULL";
res += "\n";
i++;
fromContainer = _GetSubContainer(fromContainer, 0);
}
return res;
}
public static IContainer? SearchContainer(Guid id)
=> SearchContainer(id, Root);
public static IContainer? SearchContainer(Guid id, IContainer? fromContainer)
{
if (fromContainer == null) return null;
if (fromContainer.Id == id)
return fromContainer;
if (fromContainer.IsLeaf)
return null;
return SearchContainer(id, fromContainer._GetSubContainer(0));
}
public static bool SetItemToContainer(Guid id, IContainer newContainer)
{
var container = SearchContainer(id);
if(container == null) return false;
if (container._GetSubContainer(0) == null || (container.GetContainers()![0].GetType() != newContainer.GetType()))
return false;
container.GetContainers()![0] = newContainer;
return true;
}
}
The Program and its output
Console.WriteLine(ContainerUtils.ContainersToString());
IContainer newChild2 = new Child2Container();
Console.WriteLine("Child2's Name : " + ContainerUtils.SearchContainer(ContainerUtils.AllIds[2])?.Name ?? "NULL");
Console.WriteLine("New Child2's Name : " + newChild2.Name);
ContainerUtils.SetItemToContainer(ContainerUtils.AllIds[1], newChild2);
Console.WriteLine(ContainerUtils.ContainersToString());
Output
+RootContainer_4
+Child1Container_3
+Child2Container_2
+Child3Container_1
+LeafContainer_0
Child2's Name : Child2Container_2
New Child2's Name : Child2Container_5
+RootContainer_4
+Child1Container_3
+Child2Container_5
OLD answer
I created a new test project with a simpler version of my OP one.
Here is what I ended, and yep found using an interface as a "workish" solution (I'm not completely satisfied).
Let me know what you think of it please.
The interface without generic parameter :
public interface IContainer
{
string Name => this.GetType().Name;
public Guid Id { get; init; }
public IContainer? Item { get; set; }
public bool IsLeaf => Id == Guid.Empty;
}
The base abstract class with the generic parameter :
public abstract class ContainerBase<T> : IContainer where T : IContainer
{
public Guid Id { get; init; }
public T? Item { get; set; }
IContainer? IContainer.Item { get => Item; set => Item = (T)value; }
public ContainerBase(Guid id)
{
Id=id;
}
public ContainerBase()
{
Id = Guid.NewGuid();
}
}
The starting concrete Container class
internal class RootContainer : ContainerBase<Child1Container>
{
public RootContainer(Guid id) : base(id)
{
}
public RootContainer() : base()
{
}
}
The child Container concrete classes.
In my project there is Child1Container, Child2Container and Child3Container. I only display Child1Container here. The other are the same except class name.
internal class Child1Container : ContainerBase<Child2Container>
{
public Child1Container(Guid id) : base(id)
{
}
public Child1Container() : base()
{
}
}
The endind Container (noted Leaf here) :
This is where I found the code most ugly..
internal class LeafContainer : IContainer
{
public int IntItem { get; set; }
public Guid Id { get; init ; }
/// Meh, would be nice to avoid this.
public IContainer? Item { get => null; set => Item = null; }
public LeafContainer()
{
Id = Guid.Empty;
}
}
My utility class :
internal static class ContainerUtils
{
public static Guid IdToSearch { get; set; }
private static RootContainer _root = BuildContainers();
public static RootContainer Root => _root;
private static RootContainer BuildContainers()
{
LeafContainer Leaf = new LeafContainer();
Child3Container Child3 = new Child3Container();
Child2Container Child2 = new Child2Container();
Child1Container Child1 = new Child1Container();
RootContainer Root = new RootContainer();
Root.Item = Child1;
Child1.Item = Child2;
Child2.Item = Child3;
Child3.Item = Leaf;
Leaf.IntItem = 12;
IdToSearch = Root.Id;
return Root;
}
public static IContainer? SearchContainer(Guid id)
=> SearchContainer(id, Root);
public static IContainer? SearchContainer(Guid id, IContainer? fromContainer)
{
if (fromContainer == null) return null;
if(fromContainer.Id == id)
return fromContainer;
if(fromContainer.IsLeaf)
return null;
return SearchContainer(id, fromContainer.Item);
}
}
Finally my Program :
using TestRecursiveGenerics;
var res = ContainerUtils.SearchContainer(ContainerUtils.IdToSearch);
Console.WriteLine("Searching IContainer's Id, and we found : "+ res?.Name ?? "NULL");

Generic class containing child of another generic type

The title may be a bit confusing, but I'm unsure how to phrase it differently.
I have a class of a generic type. I want the class to contain a child of the same class, but with another generic type. Something like this :
public class Test<Foo>
{
private readonly Foo _myFoo;
public Test<ChildFoo> Child { get; set; }
public Test(Foo foo)
{
_myFoo = foo;
}
}
public class Impl
{
public void FooTest()
{
var parent = new Test<string>("tester");
var child = new Test<int>(1234);
parent.Child = child;
}
}
But I can't have a Child with "ChildFoo" generic. Any other way of doing this?
Try it like this.
public class Test<T1, T2>
{
private readonly T1 _myFoo;
public T2 Child { get; set; }
public Test(T1 foo)
{
_myFoo = foo;
}
}
public class Impl
{
public void FooTest()
{
var parent = new Test<string, Test<int, object>>("tester");
var child = new Test<int, object>(1234);
parent.Child = child;
}
}
Since the first solution does not satisfy your needs I have one more idea that involves interface and let's you work with the child as if it was Test<,>.
public class Test<T1, T2> : ITest where T2 : ITest
{
private readonly T1 _myFoo;
public T2 Child { get; set; }
public void A()
{
}
public void B()
{
Child.A();
}
public Test(T1 foo)
{
_myFoo = foo;
}
}
public interface ITest
{
void A();
void B();
}
public class Impl
{
public void FooTest()
{
var parent = new Test<string, Test<int, ITest>>("tester");
var child = new Test<int, ITest>(1234);
parent.Child = child;
}
}
I would try something like this:
public class Test<T>
{
private readonly T _myFoo;
public Test(T foo)
{
_myFoo = foo;
}
}
public class ParentTest<T, TChild, TChildType> : Test<T> where TChild : Test<TChildType>
{
TChild Child { get; set; }
}
public class Impl
{
public void FooTest()
{
var parent = new ParentTest<string, Test<int>, int>("tester");
var child = new Test<int>(1234);
parent.Child = child;
}
}
This is correct way, with minimal modification of your code
public class Test<Foo,ChildFoo>
{
private readonly Foo _myFoo;
public Test<ChildFoo,ChildFoo> Child { get; set; }
public Test(Foo foo)
{
_myFoo = foo;
}
}
public class Impl
{
public void FooTest()
{
var parent = new Test<string,int>("tester");
var child = new Test<int,int>(1234);
parent.Child = child;
}
}

C# Creating a generic type validator service

I have a structure of people in an enterprise like Boss and Employee.
I just added Validator on each type to apply rules before moving forward with creation.
public class BossService : IStructMapper<People>
{
IValidatorService<Boss> _validatorService;
public BossService(IValidatorService<Boss> validatorService)
{
_validatorService = validatorService;
}
public List<Boss> Convert(string json)
{
var bossSource = JsonConvert.DeserializeObject<List<boss>>(json);
bossSource.ForEach(x => x.ApplyRules());
_validatorService.ValidateContent(new BossValidator(), bossSource);
}
}
public class BossValidatorService : IValidatorService<Boss>
{
public void ValidateContent(AbstractValidator<Boss> validator, List<Boss> bossContent)
{
foreach (var item in bossContent)
{
var result = validator.Validate(item);
if (result.IsValid) continue;
}
}
}
public interface IValidatorService<T>
{
void ValidateContent(AbstractValidator<T> validator, List<T> content);
}
public class BossValidator : AbstractValidator<Boss>
{
public BossValidator()
{
***rules for boss**
}
}
so in my program I call and it does it's job:
var bosses = new BossService(new BossValidatorService()).Convert(datafile)
For employee I created distinct EmployeeService class and EmployeeValidator :
public class EmployeeService : IStructMapper<People>
{
IValidatorService<Employee> _validatorService;
public EmployeeService(IValidatorService<Employee> validatorService)
{
_validatorService = validatorService;
}
public List<Employee> Convert(string json)
{
var employeeSource = JsonConvert.DeserializeObject<List<Employee>>(json);
employeeSource .ForEach(x => x.ApplyRules());
_validatorService.ValidateContent(new BossValidator(), bossSource);
}
}
public class EmployeeValidator : AbstractValidator<Employee>
{
public EmployeeValidator()
{
***rules for employee**
}
}
How can I simplify my code to not have to create a BossValidatorService, an EmployeeValidatorService, a ConsultantValidatorService, etc. since the ValidateContent function will be the same for each type.
You should pass the Type to the Class and use Generics as intended. I did not go to running code but it should be clear to you how to use:
var bosses = new Service<Boss>(new ValidatorService<Boss, BossValidator>()).Convert(datafile)
public class Service<T, TValidator> : IStructMapper<People> where TValidator : new()
{
IValidatorService<T> _validatorService;
public Service(IValidatorService<T> validatorService)
{
_validatorService = validatorService;
}
public List<T> Convert(string json)
{
var Source = JsonConvert.DeserializeObject<List<T>>(json);
Source.ForEach(x => x.ApplyRules());
_validatorService.ValidateContent(new TValidator<T>(), Source);
}
}
public class ValidatorService<T> : IValidatorService<T>
{
public void ValidateContent(AbstractValidator<T> validator, List<T> Content)
{
foreach (var item in Content)
{
var result = validator.Validate(item);
if (result.IsValid) continue;
}
}
}
public interface IValidatorService<T>
{
void ValidateContent(AbstractValidator<T> validator, List<T> content);
}
public class BossValidator : AbstractValidator<Boss>
{
public BossValidator()
{
***rules for boss * *
}
}
public class EmployeeValidator : AbstractValidator<Employee>
{
public EmployeeValidator()
{
***rules for employee * *
}
}

Static method call in generic manner

I have multiple classes like:
public class Base { }
public class Base1: Base { public static List<Base1> LoadFromXml(string path) }
public class Base2: Base { public static List<Base2> LoadFromXml(string path) }
Then I want to have a method like this:
public List<T> PrepareBase<T>() where T: Base { return T.Load("C:\test.xml"); }
So that I don't have to make a method for every type.
But I don't know how to accomplish this or something similar.
The problem is that I can't make the LoadFromXml method known to the base class because static inheritance is not a thing. Neither is creating a seperate interface with a static method.
Is there a way to do this or am I expecting too much?
Edit:
An example of the LoadFromXml method:
public class Base1
{
public int ID { get; set; }
public string PropertyOnlyInBase1 { get; set; }
public static List<Base1> LoadFromXml(string path)
{
List<Base1> baseList = new List<Base1>();
XDocument doc = XDocument.Load(path);
foreach(var node in doc.Descendants("Base1"))
{
Base 1 base = new Base1() { ID = node.Attributes["id"] };
base.PropertyOnlyInBase1 = node.Element("PropertyOnlyInBase1");
baseList.Add(base);
}
return baseList;
}
}
So the Base classes also have some unique properties. That's why I needed the inheritance thing in the first place.
One option is to add a GenericBase:
public abstract class Base
{
}
public static class GenericBase<T>
where T : Base
{
public static List<T> LoadFromXml(string path)
{
//Load from XML
}
}
public class Base1 : Base { }
public class Base2 : Base { }
public class Test //MainForm.cs class or whatever you want
{
public void Tester() //Load event handler or whatever you want
{
List<Base1> base1List = PrepareBase<Base1>();
}
public List<T> PrepareBase<T>() where T : Base
{ return GenericBase<T>.LoadFromXml("C:\test.xml"); }
}
Edit:
As D Stanley mentioned, it's not possible; but I made some work-around that could be helpful for you:
public abstract class Base
{
public static List<T> LoadFromXml<T>(string path) where T : Base, new()
{
List<T> baseList = new List<T>();
XDocument doc = XDocument.Load(path);
foreach (var node in doc.Descendants(typeof(T).Name))
{
T t = new T();
Dictionary<string, string> d = new Dictionary<string, string>();
foreach (var item in node.Elements())
d.Add(item.Name.ToString(), item.Value);
t.Load(d);
baseList.Add(t);
}
return baseList;
}
protected internal abstract void Load(Dictionary<string, string> elements);
}
public class Base1 : Base
{
public string CustomProp1 { get; set; }
public string CustomProp2 { get; set; }
public string CustomProp3 { get; set; }
protected internal override void Load(Dictionary<string, string> elements)
{
if (elements.ContainsKey("CustomProp1"))
CustomProp1 = elements["CustomProp1"];
if (elements.ContainsKey("CustomProp2"))
CustomProp2 = elements["CustomProp2"];
if (elements.ContainsKey("CustomProp3"))
CustomProp3 = elements["CustomProp3"];
}
}
public class Base2 : Base
{
public string CustomProp1 { get; set; }
public string CustomProp2 { get; set; }
public string CustomProp3 { get; set; }
protected internal override void Load(Dictionary<string, string> elements)
{
if (elements.ContainsKey("CustomProp1"))
CustomProp1 = elements["CustomProp1"];
if (elements.ContainsKey("CustomProp2"))
CustomProp2 = elements["CustomProp2"];
if (elements.ContainsKey("CustomProp3"))
CustomProp3 = elements["CustomProp3"];
}
}
public class Test //MainForm.cs class or whatever you want
{
public void Tester() //Load event handler or whatever you want
{
List<Base1> base1List = PrepareBase<Base1>();
}
public List<T> PrepareBase<T>() where T : Base, new()
{
return Base.LoadFromXml<T>("C:\test.xml");
}
}
I think you're correct that the class that loads these from XML should be separate from the class that's being loaded. As you said, it has no real connection to the instance.
Perhaps what you need is a separate class that loads those instances for you.
public class BaseXmlLoader<TBase> where TBase : Base
{
public List<TBase> LoadFromXml(string filePath)
{
var serializer = new XmlSerializer(typeof(TBase));
// Load your file and deserialize.
}
}
The benefits aren't huge because it's not saving you that much code. But if the LoadFromXml methods are essentially the same except for the type then you're getting something out of it.
I changed my approach to the problem and solved it using the Factory pattern. I also provided each class with an instance method SetPropertiesFromXml to handle the custom properties. Unlike the previously used method, a method like that made sense as an instance method.
Factory:
public static class BaseFactory
{
public static Base GetBase(string id)
{
switch(id) { case '1': return new Base1(); ... }
}
public static T GetBaseList<T>(string xml, string tagName) where T: Base
{
List<T> list = new List<T>();
var nodes = XDocument.Load(xml).Descendants(tagName);
foreach(XElement node in nodes)
{
var base = GetBase(node.Attribute("id").Value);
base.SetPropertiesFromXml(node);
list.Add(base as T);
}
}
}
Bases
public abstract class Base
{
public virtual void SetPropertiesFromXml(XElement node)
{
//<Set Properties like: this.Property = node.Element("key");>
}
}
public class Base1
{
public override void SetPropertiesFromXml(XElement node)
{
//<Set Custom Properties for Base1>
//Call Base to add the normal properties as well
base.SetPropertiesFromXml(node);
}
}
Call
List<Base1> list = BaseFactory.GetBaseList<Base1>("test.xml", "Base1");

Interface with List of same interface

I have the following interface:
public interface IObject{
double x {get;}
double y {get;}
List<IObject> List{get; set;}
}
and this class
public class Holder<T> where T : IObject {
private T myItem;
public void ChangeItemList(T item){
myItem.List = item.List;
}
However the compiler doesn't like the ChangeItemList method and on this line :
myItem.List = item.List;
gives me this error:
Cannot convert source type 'List<T>' to target type 'List<IObject>'
Why can't I do it and what is a good solution for this scenario?
thank you
I am not sure what you want to achieve but the following compiles and runs without exceptions:
class Program
{
static void Main(string[] args)
{
var holder = new Holder<IObject>();
holder.MyItem = new Object { List = new List<IObject>() };
holder.ChangeItemList(new Object { List = new List<IObject>() });
}
}
public class Object : IObject
{
public List<IObject> List { get; set; }
}
public interface IObject
{
List<IObject> List { get; set; }
}
public class Holder<T> where T : IObject
{
public T MyItem { get; set; }
public void ChangeItemList(T item)
{
MyItem.List = item.List;
}
}
Try to do this one- worked for me. The problem i had that myItem was null.
public class Holder<T> where T : IObject
{
private T myItem = Activator.CreateInstance<T>();
public void ChangeItemList(T item)
{
myItem.List = item.List;
}
}

Categories