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;
}
}
Related
I have currently a problem
I have 1 Interface with two types of argument like this
ITestInterface<ArgumentA>
ITestInterface<ArgumentB>
this interface has only the argument as different
I would like to pass this interface to an constructor of a class. sth like this
public class MyClass
{
public ITestInterface<object> MyInterface {get; set;}
public MyClass(ITestInterface<ArgumentA> testInterfaceA){
this.MyInterface = testInterfaceA as ITestInterface<object>;
this.MyTestInterface.SomeEvent += this.OnSubcribe;
}
public MyClass(ITestInterface<ArgumentB> testInterfaceB){
this.MyInterface = testInterfaceB as ITestInterface<object>;
this.MyTestInterface.SomeEvent += this.OnSubcribe;
}
public void OnSubcribe(){
//Work to do here, dont care about what argument the interface has.
}
}
and to call the MyClass constructor I have sth like this:
public List<MyClass> ClassList = new();
public void testMethod(){
var interA = getInterfaceWithArgumentA();
var myClassA = new MyClass(interA);
var interB = getInterfaceWithArgumentB();
var myClassB = new MyClass(interB);
}
So the problem is i am not able to cast the interface argument to object. I dont need to differenciate the argument either. I just want to avoid to have 2 properties of MyInterface like (MyInterfaceA, MyInterfaceB).
I need also to consider that maybe in the future I will have more type of Argument so maybe to have multiple properties like MyInterfaceA, MyInterfaceB, MyInterfaceC and also multiple constructor for each Interfaceargument type would be a mess.
I just thought about have a Baseclass and the ArgumentA and ArgumentB class derived from it so the cast would work but its not like that.
How would I solve this problem ?
Many Thanks
I think you have not provided what getInterfaceWithArgumentB() and getInterfaceWithArgumentA() method doing. I am making few assumption.
To solve your problem Generic will help.
Following is the example of it.
public class MyClass<T>
{
public ITestInterface<T> MyInterface { get; set; }
public MyClass(ITestInterface<T> testInterfaceA)
{
this.MyInterface = testInterfaceA;
this.MyInterface.SomeEvent += MyInterface_SomeEvent;
}
private void MyInterface_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}
public class ArgumentA
{
public string Name { get; set; }
}
public class ArgumentB
{
public int Id { get; set; }
}
public interface ITestInterface<T>
{
T Data { get; set; }
event EventHandler SomeEvent;
void OnSomeEvent();
}
public class TestInterface<T> : ITestInterface<T>
{
public T Data { get ; set; }
public event EventHandler SomeEvent;
public void OnSomeEvent()
{
if(SomeEvent != null)
SomeEvent(Data, EventArgs.Empty);
}
}
You can use it like following.
MyClass<ArgumentA> myClass = new MyClass<ArgumentA>(
new TestInterface<ArgumentA>()
{
Data = new ArgumentA() { Name = "test" }
});
MyClass<ArgumentB> myClas2 = new MyClass<ArgumentB>(
new TestInterface<ArgumentB>()
{
Data = new ArgumentB() { Id = 10 }
});
myClas2.MyInterface.OnSomeEvent();
myClass.MyInterface.OnSomeEvent();
UPDATE
class Program
{
static void Main(string[] args)
{
ObservableCollection<MyClass> items = new ObservableCollection<MyClass>();
MyClass<ArgumentA> myClass = new MyClass<ArgumentA>(
new TestInterface<ArgumentA>()
{
Data = new ArgumentA() { Name = "test" }
});
MyClass<ArgumentB> myClas2 = new MyClass<ArgumentB>(
new TestInterface<ArgumentB>()
{
Data = new ArgumentB() { Id = 10 }
});
items.Add(myClass);
items.Add(myClas2);
myClas2.MyInterface.OnSomeEvent();
myClass.MyInterface.OnSomeEvent();
}
}
public class MyClass
{
public ITestInterface MyInterface { get; set; }
}
public class MyClass<T> : MyClass
{
public MyClass(ITestInterface<T> testInterfaceA)
{
this.MyInterface = testInterfaceA;
this.MyInterface.SomeEvent += MyInterface_SomeEvent;
}
private void MyInterface_SomeEvent(object sender, EventArgs e)
{
Console.WriteLine(sender);
}
}
public class ArgumentA
{
public string Name { get; set; }
}
public class ArgumentB
{
public int Id { get; set; }
}
public interface ITestInterface
{
event EventHandler SomeEvent;
void OnSomeEvent();
}
public interface ITestInterface<T> : ITestInterface
{
T Data { get; }
}
public class TestInterface<T> : ITestInterface<T>
{
public T Data { get; set; }
public event EventHandler SomeEvent;
public void OnSomeEvent()
{
if (SomeEvent != null)
SomeEvent(Data, EventArgs.Empty);
}
}
I have a ParentClass. Two classes are inherit from it, FirstChildClass and SecondChildClass. A class MultipleValueTypes contains a Dictionary and a method that adds values to it. My intention is to be able to pass values of different classes, which inherit from the same abstract class to the value parameter of the Dictionary. Therefore, I initialize the dictionary with the value List<ParentClass> so that I would be able to add objects made with the child classes to the Dictionary. I can do this, but I cannot access them, therefore in the abstract class I create a way to tell them apart, a virtual method that both the children classes override to return their own class type.
I test the values they return against the enum itself and based on whether the condition is fulfilled, the object would be casted as what it is instead of a List<ParentClass>. Is this the wrong approach? Is this impossible?
I think it should work, because in my thinking the FirstObject and SecondObject are still objects of their respective classes, so casting should work and I should be able to access the overridden method.
What doesn't work: I cannot access the method that returns what type of class it is, because it only gets methods from the List<ParentClass>.
What I've tried so far: searching for a way to access the method, but I did not find any.
What I still need help with: everything mentioned above.
public abstract class ParentClass
{
public string Name { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
}
public class FirstChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public FirstChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the FirstChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public SecondChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the SecondChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public Dictionary<string, List<ParentClass>> ADictionary = new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if (!ADictionary.ContainsKey(Name))
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
class Program
{
static void Main(string[] args)
{
FirstChildClass FirstObject = new FirstChildClass("FirstObject");
SecondChildClass SecondObject = new SecondChildClass("SecondObject");
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if(TestDictionary.ADictionary["FirstObject"].TypeOfClass() == ParentClass.ChildClasses.FirstChildClass) ///List<ParentClass>' does not contain a definition for 'TypeOfClass' and no accessible extension method 'TypeOfClass' accepting a first argument of type 'List<ParentClass>' could be found (are you missing a using directive or an assembly reference?)
{
TestDictionary.ADictionary["FirstObject"] = (FirstChildClass)TestDictionary.ADictionary["FirstObject"]; ///Cannot convert type 'System.Collections.Generic.List<Dictionary.ParentClass>' to 'Dictionary.FirstChildClass
}
}
}
You forgot to use indexer of the list value of the key of the dictionary here:
==> TestDictionary.ADictionary["FirstObject"][0]
Here is your code now refactored too:
class Program
{
static void Main(string[] args)
{
var FirstObject = new FirstChildClass("FirstObject");
var SecondObject = new SecondChildClass("SecondObject");
FirstObject.ReturnMessage();
SecondObject.ReturnMessage();
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if ( TestDictionary.ADictionary["FirstObject"][0].TypeOfClass()
== ParentClass.ChildClasses.FirstChildClass )
{
TestDictionary.ADictionary["FirstObject"][0]
= (FirstChildClass)TestDictionary.ADictionary["FirstObject"][0];
}
Console.ReadKey();
}
}
public abstract class ParentClass
{
public string Name { get; set; }
public string RandomValue { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public virtual void ReturnMessage()
{
Console.WriteLine($"This is the {this.GetType().Name} instance");
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
}
public class FirstChildClass : ParentClass
{
public FirstChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
public SecondChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public readonly Dictionary<string, List<ParentClass>> ADictionary
= new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if ( !ADictionary.ContainsKey(Name) )
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
If the intention is to cast the whole list from List<ParentClass> to List<FirstChildClass> and List<SecondChildClass>, then Linq is your friend, just use the Cast function:
List<FirstChildClass> firstChildClasses = TestDictionary.ADictionary["FirstObject"]
.Cast<FirstChildClass>().ToList();
List<SecondChildClass> secondChildClasses = TestDictionary.ADictionary["SecondObject"]
.Cast<SecondChildClass>().ToList();
I want to implement an interface that's quite simple :
public interface IProfession
{
List<string> jobSkills { get; set; }
void setSkills();
}
public class artisan : IProfession
{
int money = 1200;
public List<string> jobSkills;
public void setSkills(){
jobSkills.Add("baratin");
jobSkills.Add("marchandage");
jobSkills.Add("monde_naturel");
jobSkills.Add("royaume_natal");
jobSkills.Add("sagacite");
jobSkills.Add("statut");
jobSkills.Add("statut");
}
}
Vstudio tells me that Models.artisan does not implement interface member Models.IProfession.jobSkills.
Why? I have tried this too :
public class artisan : IProfession
{
int money = 1200;
protected List<string> jobSkills;
public List<string> _jobSkills
{
get { return jobSkills;}
set { jobSkills = value; }
}
public void setSkills(){
jobSkills.Add("baratin");
jobSkills.Add("marchandage");
jobSkills.Add("monde_naturel");
jobSkills.Add("royaume_natal");
jobSkills.Add("sagacite");
jobSkills.Add("statut");
jobSkills.Add("statut");
}
}
but it does not work either (same error). can someone explain what I'm missing?
Thank you
Your interface requires a property jobSkills. You will need to implement a property then:
public interface IProfession
{
List<string> JobSkills { get; set; }
void SetSkills();
}
public class Artisan : IProfession
{
public List<string> JobSkills { get; set; };
public void SetSkills()
{
}
}
You need
public List<string> jobSkills { get; set; }
Also in your method you need to initialize the list.
public void setSkills()
{
if(jobSkills == null)
jobSkills = new List<string>();
jobSkills.Add("baratin");
jobSkills.Add("marchandage");
jobSkills.Add("monde_naturel");
jobSkills.Add("royaume_natal");
jobSkills.Add("sagacite");
jobSkills.Add("statut");
jobSkills.Add("statut");
}
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");
This question already has answers here:
Interface with List of same interface
(2 answers)
Closed 8 years ago.
I have the following interface:
public interface IObject
{
double x { get; }
double y { get; }
Holder<IObject> Holder { get; set; }
}
and this class
public class Holder<T> where T : IObject
{
private List<T> items;
public void AddItem(T item){
items.Add(item);
item.Holder = this;
}
However the compiler doesn't like the AddItem method and on this line :
item.Holder = this;
gives me this error:
Cannot convert source type 'Holder<T>' to target type 'Holder<IObject>'
Why can't I do it and what is a good solution for this scenario?
thank you
You have to bear in mind the way Genrics works in C#, The compiler create a class of the specified type, and because of that you have the error.
To explain more, given the following example:
public class InterfaceImplementation : IObject
{
}
and then some where you do :
var genericInitialisation = new Holder<InterfaceImplementation>();
The compiler at compile time will create a class HolderInterfaceImplementation replacing all accurances of the T generic parameter.
so after compilation you will have this class:
public class HolderInterfaceImplementation
{
private ListInterfaceImplementation items;
public void AddItem(InterfaceImplementation item){
items.Add(item);
item.Holder = this;
}
And item.Holder would be HolderIObject type, so the compiler report an error about not being able to convert HolderInterfaceImplementation to HolderIObject wich is logical.
After explaining the theory the solution comes naturaly and here is an example:
public interface IObject<T> where T : IObject<T>
{
double x { get; }
double y { get; }
Holder<T> Holder { get; set; }
}
public class Holder<T> where T : IObject<T>
{
public Holder()
{
items = new List<T>();
}
private List<T> items;
public void AddItem(T item)
{
items.Add(item);
item.Holder = this;
}
}
public class Implementation : IObject<Implementation>
{
public double x
{
get { return 0; }
}
public double y
{
get { return 0; }
}
public Holder<Implementation> Holder
{
get;
set;
}
}
static void Main(string[] args)
{
var t = new Holder<Implementation>();
t.AddItem(new Implementation());
Console.ReadKey();
}
If it was possible to convert that would be a type system hole:
public class Holder<T> where T : IObject
{
public T SomeField;
}
...
var holder = new Holder<IObjectSubType2>();
Holder<IObject> dummy = holder; //assuming that this works
dummy.SomeField = new IObjectSubType1(); //violates type safety
IObjectSubType2 converted = holder.SomeField;
As you can see I was able to convert an instance of IObjectSubType1 to an IObjectSubType2.
That's why this does not type check.