Overloading virtual generic method - c#

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.

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>
{
}

No properties are mapped for type using csvHelper

I have two methods that return list of EmployeeCsv and CardCsv.
public class EmployeeCsv
{
public string EmployeeId { get; set; }
public string EmployeeName { get; set; }
}
public class CardCsv
{
public string MaxCharge { get; set; }
public string MaxDiscount { get; set; }
}
public List<EmployeeCsv> GetEmployeeList() {} // returns list of EmployeeCsv
public List<CardCsv> GetCardList() {} // returns list of CardCsv
I wanted to declare one type list for those two methods.
So I changed them like below
public interface ITest {}
public class EmployeeCsv : ITest
{
public string EmployeeId { get; set; }
public string EmployeeName { get; set; }
}
public class CardCsv : ITest
{
public string MaxCharge { get; set; }
public string MaxDiscount { get; set; }
}
public List<ITest> GetEmployeeList() {}
public List<ITest> GetCardList() {}
Main:
void main()
{
var records = new List<ITest>();
records = GetEmployeeList();
using (var writer = new StreamWriter(fileName))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.Configuration.ShouldQuote = (field, context) => true;
csv.WriteRecords(records); // error here
}
}
I get an error on saving after adding interface to those two classes.
How can I fix this?
The problem here is that CsvHelper doesn't know the instance of the list items. You're telling it to process ITest items.
Consider the following:
var records = new List<ITest> { new EmployeeCsv(), new CardCsv() };
This is valid code. Now put yourself in CsvHelper's position. How would it create a CSV out of the items? Would it handle them as Employee, or Card? Neither. All it knows is that the items were ITest (a blank interface). Hence your error.
Instead complicating it with ITest, you're better off leaving the list items as their concrete types, but treating them as IEnumerable.
// Leave them as the derived types
public List<EmployeeCsv> GetEmployeeList() { .. }
public List<CardCsv> GetCardList() { .. }
void Main() {
// Notice the IEnumerable so we can reuse WriteToFile()
IEnumerable items = GetEmployeeList();
WriteToFile(items); // employees
items = GetCardList();
WriteToFile(items); // cards
}
void WriteToFile(IEnumerable records) {
...
csv.WriteRecords(records);
}
This way, CsvHelper can actually inspect the list and figure out the type, without the ITest confusion.
Edit:
You should probably create a generic method, that way you can limit your items to ITest if you really want to, or you can leave it open.
// This needs to stay as its concrete type.
public List<EmployeeCsv> GetEmployeeList() { .. }
void Main() {
WriteToFile(GetEmployeeList());
}
// Get rid of the 'where' to make it accept things other than ITest.
void WriteToFile<T>(IEnumerable<T> records) where T : ITest
{ ...
csv.WriteRecords(records);
}

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.

calling derived methods on a baseclass collection

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.

How do I convert a List<interface> to List<concrete>?

I have an interface defined as:
public interface MyInterface {
object foo { get; set; };
}
and a class that implements that interface:
public class MyClass : MyInterface {
object foo { get; set; }
}
I then create a function that returns a ICollection like so:
public ICollection<MyClass> Classes() {
List<MyClass> value;
List<MyInterface> list = new List<MyInterface>(
new MyInterface[] {
new MyClass {
ID = 1
},
new MyClass {
ID = 1
},
new MyClass {
ID = 1
}
});
value = new List<MyClass>((IEnumerable<MyClass>) list);
return value;
}
It would compile but would throw a
Unable to cast object of type
'System.Collections.Generic.List1[MyInterface]'
to type
'System.Collections.Generic.IEnumerable1[MyClass]'.
exception. What am I doing wrong?
A List<MyInterface> cannot be converted to a List<MyClass> in general, because the first list might contain objects that implement MyInterface but which aren't actually objects of type MyClass.
However, since in your case you know how you constructed the list and can be sure that it contains only MyClass objects, you can do this using Linq:
return list.ConvertAll(o => (MyClass)o);
But a List<MyInterface> is emphatically not a List<MyClass>.
Think:
interface IAnimal { }
class Cat : IAnimal { }
class Dog : IAnimal { }
var list = new List<IAnimal> { new Cat(), new Dog() };
Then
var cats = (List<Cat>)list;
Absurd!
Also,
var cats = list.Cast<Cat>();
Absurd!
Further
var cats = list.ConvertAll(x => (Cat)x);
Absurd!
Instead, you could say
var cats = list.OfType<Cat>();
You could use Cast<> extension method:
return list.Cast<MyClass>();
I find Automapper very useful for converting interfaces to concrete classes.
It is possible and that's where the generics shine!
Here is a simple example:
public interface ICountable
{
int Count { get; set; }
}
public class PopularName : ICountable
{
public string Name { get; set; }
public int Count { get; set; }
}
public class PopularSize : ICountable
{
public int Size { get; set; }
public int Count { get; set; }
}
And now you need to declare your method (or your class) generic like this:
public bool HasAnyValue<T>(List<T> countableModel) where T : ICountable
{
return countableModel.Count > 0;
}

Categories

Resources