calling derived methods on a baseclass collection - c#

I have one abstract class named A, and other classes (B, C, D, E, ...) that implements A.
My derived classes are holding values of different types.
I also have a list of A objects.
abstract class A { }
class B : class A
{
public int val {get;private set;}
}
class C : class A
{
public double val {get;private set;}
}
class D : class A
{
public string val {get;private set;}
}
class Program
{
static void Main(string[] args)
{
List list = new List { new B(), new C(), new D(), new E() };
// ...
foreach (A item in list)
{
Console.WriteLine(String.Format("Value is: {0}", item.val);
}
}
}
...where the .val is not known by the base-class ofc.
How can i get this dynamic behaviour? I don't want to use getType in a long switch/if-statements.

If you just want to get the string representation of val i recoment overriding ToString in each of the sub classes
public override string ToString()
{
return val.ToString();
}
either way if you want the data in a sub class you need to represent it in the base class as some type they all have in common (like object). and you could do it like this
abstract class A
{
public abstract object GetValue();
}
class B : class A
{
public int val {get;private set;}
public override object GetValue()
{
return val;
}
}

Try this:
using System;
using System.Collections.Generic;
abstract class A
{
public abstract dynamic Val { get; set; }
}
class B : A
{
public override dynamic Val { get; set; }
}
class C : A
{
public override dynamic Val { get; set; }
}
class D : A
{
public override dynamic Val { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list = new List<A> { new B(), new C(), new D() };
// ...
foreach (A item in list)
{
Console.WriteLine(String.Format("Value is: {0}", item.Val));
}
}
}

abstract class A { public string val { get; set; } }
class B : A
{
public int val {get;private set;}
}
class C : A
{
public double val {get;private set;}
}
class D : A
{
public string val {get;private set;}
}
class Program
{
static void Main(string[] args)
{
List<object> list = new List<object> { new B(), new C(), new D() };
// ...
foreach (A item in list)
{
Console.WriteLine(String.Format("Value is: {0}", item.val));
}
}
}

If val is not a member of the base class then you can't access it on a reference of that type. Those three derived classes may all have a member named val but it is NOT the same member so it cannot be treated like it is. What you could do is declare a generic class and make that val property of the generic type but then you couldn't create a List of that type. Basically, what you want to do is not possible. It's not based on inheritance and it's not based on generics. It sounds convenient but it's not logical.

Related

Cast generic class object to non-generic

I have 2 classes:
public class GenericClass<T>
{
public T Item {get;set;}
}
public class StringClass
{
public string Item {get;set;}
}
now i have a GenericClass object and i need to cast it to StringClass object:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)genericObj; // <---
How to cast / convert from generic class to specific one?
You can't cast one type to the other because the types are unrelated.
You could, however, define a conversion operator:
public class StringClass
{
public string Item { get; set; }
public static explicit operator StringClass(GenericClass<string> generic)
=> new StringClass { Item = generic.Item };
}
Which would allow this syntax:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)genericObj;
You can't. You would need common inherited type or implement an interface.
With inheritance:
public class GenericClass<T>
{
public T Item {get;set;}
}
public class StringClass : GenericClass<string>
{
}
if your really need it, you can do this way for examle
var stringObj = new StringClass(genericObj);
public class StringClass
{
public string Item { get; set; }
public StringClass(GenericClass<string> genericClass)
{
Item=genericClass.Item;
}
public StringClass(){}
}
or this is more flexible
public interface IGenericClass<T>
{
public T Item { get; set; }
}
public class GenericClass<T>:IGenericClass<T>
{
public T Item { get; set; }
}
public class StringClass
{
public string Item { get; set; }
public StringClass(IGenericClass<string> genericClass)
{
Item=genericClass.Item;
}
public StringClass(){}
}
Using this answer:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)Convert.ChangeType(genericObj, typeof(StringClass));
Finally i solved using ICloneable,
Here i have a base class named GenericClass, a generic class named GenericClassT, and a class named StringClass.
Inheritance is:
GenericClass <- GenericClassT <- StringClass
Using ICloneable implementation on GenericClass and GenericClassT, adding a CreateObject and CopyTo methods i reach the final goal:
var genericObj = new GenericClass<string>();
var stringObj = (StringClass)genericObj.Clone<StringClass>();
class definitions:
public class GenericClass: ICloneable
{
public string Id {get;set;}
protected virtual ApiRequestResult CreateObject()
{
return new GenericClass();
}
protected virtual void CopyTo(GenericClass obj)
{
obj.Id = Id;
}
public virtual object Clone()
{
var obj = CreateObject();
CopyTo(obj);
return obj;
}
public virtual object Clone<T>() where T: GenericClass
{
var obj = (GenericClass)Activator.CreateInstance(typeof(T));
CopyTo(obj);
return obj;
}
}
public class GenericClass<T>: GenericClass
{
public T Data {get; set;}
protected override GenericClass CreateObject()
{
return new GenericClass<T>();
}
protected override void CopyTo(GenericClass obj)
{
base.CopyTo(obj);
((GenericClass<T>)obj).Data = Data;
}
}
public class StringClass: GenericClass<string>
{
}

Generic method to map different object

I would like to create a generic method that can convert an object to a different type. I could not find any solutions for this scenario. Is this possible in C#?
class A
{
public string Name { get; set; }
}
class A1: A
{
public string ConnectionString { get; set; }
}
class B
{
public string DBName { get; set; }
public string DBConnectionString { get; set; }
}
void Main()
{
A obj = //data
var res = APIToBackEndModel<A, B>(obj);
//Do something
A1 obj1 = //data
var res1 = APIToBackEndModel<A1, B>(obj1);
}
private TResult APIToBackEndModel<T, TResult>(T objTo)
{
(TResult)DBName = (T)objTo.Name;
//OR
var obj = new TResult
{
DBName = (T)objTo.Name
}
}
This did not help me.
You won't be able to do it completely generic, as you rely on certain properties to exist. But you knowing these properties exist, is not enough. You have to guarantee the compiler, they exist. You can do this with Constraints on type parameters. With their help, you can define, that the generic types you use, will have certain properties (for instance implement an interface or inherit from a class).
interface InterfaceIn {
string p1 {get;set;}
void m1();
}
interface InterfaceOut {
string p2 {get;set;}
void m2();
}
class ConcreteIn : InterfaceIn {
public string p1 {get;set;}
public void m1() {}
}
class ConcreteOut1 : InterfaceOut {
public string p2 {get;set;}
public void m2() {}
}
class ConcreteOut2 : InterfaceOut {
public string p2 {get;set;}
public void m2() {}
}
class Program
{
static void Main(string[] args)
{
var a = new ConcreteIn{p1 = "some value"};
var b = mapIt<ConcreteIn, ConcreteOut1>(a);
var c = mapIt<ConcreteIn, ConcreteOut2>(a);
}
public static V mapIt<U, V>(U val) where U: InterfaceIn where V: InterfaceOut, new() {
var res = new V {p2 = val.p1};
return res;
}
}
Depending on how much properties and combinations you have, this may be enough. Or you may be better off with something like Automapper as Hans Kesting suggested. Or, if you can't group together some mappings, you will have to implement every mapping yourself.

Overloading virtual generic method

I'd like to ask if someone can help me.
I have base generic class
public class Base<T> where T : new()
{
public int ID { get; set; }
public string Name { get; set; }
public virtual string Foo()
{
throw new NotImplementedException("");
}
}
Then I have
public class A : Base<A>
{
public override string Foo()
{
return string.Empty;
}
}
and in my main code I would like to do something like:
A entity = new A();
var x = entity.Foo();
List<A> entityList = new List<A>();
var y = entityList.Foo();
my code works for entity and x, but I'd like to overload Foo to be called also on a list. Can someone help?
For such things (when you need to extend existing class without modifying source code of it) you can create extension method, for example
public static class BaseExtensions
{
public static string Foo<T>(this IEnumerable<Base<T>> items) where T : new()
{
var builder = new StringBuilder();
foreach (var item in items)
{
builder.Append(item.Foo());
}
return builder.ToString();
}
}
that concatenates all Foo results of items in array/list.

Interface design implementation error: ... cannot implement ... because it does not have a matching return type

I have a few classes in Library1: Class A, Class B, etc. that are used by classes above.
public class A
{
int VarA1;
}
public class B
{
List<A> SetA {get; set; }
void MethodB1()
{
...
this.SetA = new List<A>;
...
}
}
Now I want to have an interface for that Library1, so there can be other implementations. Calling the interface library ILibrary:
public interface IA
{
int VarA1 {get; set; }
}
public interface IB
{
List<IA> SetA { get; set; }
void MethodB1();
}
which are being implemented in Library1:
public class A : IA
{
int VarA1{ get; set; }
}
public class B : IB
{
List<IA> SetA {get; set; }
void MethodB1()
{
...
this.SetA = new List<A>;
...
}
}
But I am getting a compilation error with this code:
Library1.B.SetA cannot implement ILibrary.IB.SetA because it does not have a matching return type.
I also tried:
public class B : IB
{
List<A> SetA {get; set; }
void MethodB1()
{
...
this.SetA = new List<A>;
...
}
}
But that didn't resolve the issue (same error message). Why is this giving this error and how can I resolve it?
As the error message indicates, in order to comply with the interface, B.MethodB1 will have to return a type of IA, like this:
public class B : IB
{
public IA MethodB1() { ... }
}
An alternative is to declare IB as a generic interface like this:
public interface IB<out T> where T : IA
{
public T MethodB1();
}
And then B like this:
public class B : IB<A>
{
public A MethodB1() { ... }
}
Regarding your updated question, your issue is still the same, and so are the solutions. Either do something like this:
public class B : IB
{
public List<IA> SetA {get; set; }
public void MethodB1()
{
...
this.SetA = new List<IA>();
...
}
}
Or like this:
public interface IB<T> where T : IA
{
List<T> SetA { get; set; }
void MethodB1();
}
public class B : IB<A>
{
public List<A> SetA {get; set; }
public void MethodB1()
{
...
this.SetA = new List<A>();
...
}
}
The implementation of a method from an interface must return the exact same type, and IA is not the same as A. They have to absolutely match so it must return IA. However your B implementation of MethodB1 does not have a body and the class is not abstract so you will still get an error.
List<A> does not inherit from or implement List<IA>.
The interface IB requires a List<IA> property. The class B has a List<A> property.
Consider:
interface IAnimal()
{
public void HaveLunch();
}
class Zebra:IAnimal
class Lion:IAnimal
interface IZoo
{
List<IAnimal> Zebras {get;set;}
List<IAnimal> Lions {get;set;}
}
public class Zoo
: IZoo //does not work
{
List<Zebra> Zebras {get;set;}
List<Lion> Lions {get;set;}
}
//...
IZoo myZoo = new Zoo;
myZoo.Zebras.Add(new Lion()); //because of this.
the other answers have already said why this will not work:
An inherited property has to use the exact same type as the parent
You cannot assign List<IA> myList = new List<A>();,
you must use the same type. This is because List is not covariant.
So you will have to use IA instead of A throughout your code, and only use the public methods accessible to IA
There is however a way to make it work, while still having access to A, if you change the type of ASet to IEnumerable<IA>:
you can assign IEnumerable<IA> myList = new List<A>();
because IEnumerable supports covariance, since C# 4.0
IEnumerable does not support all the methods that List does, for example you cannot add more elements to an IEnumerable. This is unfortunately necessary to make covariance work. You can however internally use a List inside class B, and only present the IEnumerable to the outside.
public interface IB
{
IEnumerable<IA> SetA { get; set; }
void MethodB1();
}
public class B : IB
{
private List<A> listA;
public IEnumerable<IA> SetA
{
get {return listA;}
set {throw new NotImplementedException();}
// the setter is somewhat inelegant,
// if you do not need the setter
// you should probably leave it out of the interface entirely
}
public void MethodB1()
{
this.listA = new List<A>()
}
}

Common base class initialization

Take the scenario
BaseA -> SubB -> SubSubC
Explanation: SubSubC class inherits SubB class. The SubB class inherits BaseA class
BaseA -> SubD -> SubSubE
Explanation: SubSubE class inherits SubD class. The SubB class inherits BaseA class
So..on..
So there are many class that has its grand parent class as BaseA . The BaseA class has some properties that are common to all the methods. ex: CustomerID, LastLogin, UniqueName etc.
This is how the class is designed in the service which I'm consuming.
My doubt is While calling the service methods, all the methods would expect a parameter of any SubSub class. Can anyone please tell me, is there any way if I could assign values to the properties of the BaseA in one place so that while creating the SubSub objects I did not need to fill the base properties each time?
I'm using C# as my language.
Code:
public class BaseA
{
public int CustomerId { get; set; }
public string UniqueName { get; set; }
}
public class SubB : BaseA
{
}
public class SubSubC : SubB
{
}
public class SubD : BaseA
{
}
public class SubSubE : SubD
{
}
public class MyMain
{
public void SendRequestToService1()
{
(new MyServiceObject()).ServiceMethod1(new SubSubC());
}
public void SendRequestToService2()
{
(new MyServiceObject()).ServiceMethod2(new SubSubE());
}
}
In the above code, in SendRequestToService1 and SendRequestToService2 , i need to initialise the base class properties CustomerId and UniqueName.
Ex:
(new SubSubC(){ CustomerId=2, UniqueName="XXBB" });
If there are many methods, I need to initialize these properties each time for their respective classes. Is there a way I can initialize the base properties CustomerId and UniqueName in one place so that the inheriting classes(SubSubC,SubSubE here) no need to initialize when their objects are created?
Are you looking for the following functionality?
//dummy class replacing the service object and it's methods
public class MyServiceObject
{
public void ServiceMethod1(SubSubC param)
{ }
public void ServiceMethod2(SubSubE param)
{ }
}
public class BaseA
{
public int CustomerId { get; set; }
public string UniqueName { get; set; }
}
public class SubB : BaseA
{
}
public class SubSubC : SubB
{
}
public class SubD : BaseA
{
}
public class SubSubE : SubD
{
}
public class MyMain
{
//declare the SubSub objects
//SubSubC subSubC;
//SubSubE subSubE;
BaseA baseA;
public MyMain()
{
//assign the values to each class in the MyMain contrsuctor
baseA = new BaseA { CustomerId = 2, UniqueName = "XXBB" };
}
public void SendRequestToService1()
{
var subSub=new SubSubC();
(new MyServiceObject()).ServiceMethod1(Initialize(subSub));
}
public void SendRequestToService2()
{
var subSub = new SubSubE();
(new MyServiceObject()).ServiceMethod2(Initialize(subSub));
}
private T Initialize<T>(T subSub) where T:BaseA
{
subSub.CustomerId = baseA.CustomerId;
subSub.UniqueName = baseA.UniqueName;
return subSub;
}
}
class Program
{
static void Main(string[] args)
{
MyMain myMain = new MyMain();
myMain.SendRequestToService1();
myMain.SendRequestToService2();
}
}
Are you asking about calling base constructors? If so:
class SubSubC : SubB
{
public object CProperty { get; private set; }
public SubSubC(object cProperty, string bProperty, int id) : base(bProperty, id)
{
CProperty = cProperty;
}
}
class SubB : BaseA
{
public string BProperty { get; private set; }
public SubB(string bProperty, int id) : base(id)
{
BProperty = bProperty;
}
}
class BaseA
{
public int ID { get; private set; }
public BaseA(int id)
{
ID = id;
}
}
Or are you asking about initializing objects in a method? If so (assume the setters are public in the following code, unlike in the preceding):
void SetSubSubCProperties(SubSubC c, object cProperty, string bProperty, int id)
{
c.CProperty = cProperty;
SetSubBProperties(c, bProperty, id);
}
void SetSubBProperties(SubB b, string bProperty, int id)
{
b.BProperty = bProperty;
SetBaseAProperties(b, id);
}
void SetBaseAProperties(BaseA a, int id)
{
a.ID = id;
}
Ok, Alex Filipovici's answer, it looks like you want to initialize an instance of a derived class by copying the base class properties from an instance of a different derived class. In that case, to reduce the duplication in Alex's answer, you can do this:
void Initialize(BaseA source, BaseA target)
{
target.CustomerID = source.CustomerID;
target.UniqueName = source.UniqueName;
}
Then, to modify his example:
public void SendRequestToService1()
{
var subSub = new SubSubC();
Initialize(this.baseA, subSub);
(new MyServiceObject()).ServiceMethod1(subSub);
}
public void SendRequestToService2()
{
var subSub = new SubSubE();
Initialize(this.baseA, subSub);
(new MyServiceObject()).ServiceMethod2(subSub);
}
Not sure I understand your question.
public class A {
public int ID { get; set; }
}
public class B : A {
}
you can do B b = new B() and then b.ID = 12.
Or, if you have a method that gets a parameter of type A in your service you can change the value in the same way.
public void doSomething(A a) {
a.ID = 12;
}
and call the method with instances of B - doSomething(new B())

Categories

Resources