How can I make this function generic?
At the moment this method retrieves a list of type item. What I want to do is to call on this method, with a generic datatype, like Item, Category or Group. All of these has the same property name.
How can I do this?
In logic / service layer with reference to the Data Layer:
public class TaskHandler : ITaskHandler
{
public async Task<List<newDataType>> Handler(List<Item>() items)
{
var newList = new List<newDataType>();
foreach (var item in items)
{
newList.Add(new Item
{
ID = item.ID,
Name = item.Status,
Retrieved = DateTime,
});
}
return newList ;
}
}
In dataaccess layer
Datatype1.cs
public class Datatype1
{
public int ID{ get; set; }
public string Name{ get; set; }
public string Group{ get; set; }
}
Datatype2.cs
public class Datatype2
{
public int ID{ get; set; }
public string Name{ get; set; }
public string Group{ get; set; }
}
Datatype3.cs
public class Datatype3
{
public int ID{ get; set; }
public string Name{ get; set; }
public string Group{ get; set; }
}
As all of your types have the same property, you should have a common base-class or interface for them. Then you can easily add a generic constraint to your method:
public async Task<List<T>> Handler<T>(List<Item> items) where T: MyInterface, new()
{
var newList= new List<T>();
foreach (var item in items)
{
newList.Add(new T
{
ID = item.ID,
Name = item.Status,
Retrieved = DateTime,
});
}
// ...
}
with
interface MyInterface
{
// the common properties
}
and
class Item : MyInterface { ...}
class Category : MyInterface { ...}
class Group : MyInterface { ...}
Apart from this I can´t see why your method is async at all, as there´s nothing that can be awaited here.
Your code is async although there is no calls to async. It returns a "message" although there is no reference to any "message" variable. The code is pretty unreadable so its hard to know exactly what you want.
But you need to wrap the method in a generic class. Maybe something like this is what you want.
public class Foo<T> where T : new()
{
public IEnumerable<T> Handler(IEnumerable<T> items)
{
var list = new List<T>();
foreach (var item in items)
{
list.Add(new T
{
ID = item.ID,
Name = item.Status,
Retrieved = DateTime.Now,
});
}
return list;
}
}
If all those classes have the same method named Handler do something like you define a parameter T on the interface level, and your methods can use this parameter in their prototype, so any class that will be implementing this interface will naturally implement the parameter T within its own methods.
interface IBaseInterface<T>
{
Task<List<T>> Handler(List<T> items);
// the common properties
}
and then do:
public class A : IBaseInterface<A>
{
public A() { }
public async Task<List<A>> Handler(List<A> items)
{
var newList= new List<A>();
foreach (var item in items)
{
newList.Add(new A
{
ID = item.ID,
Name = item.Status,
Retrieved = DateTime,
});
}
// ...
}
}
or totally if you want make that Handler as a generic method you can do something like:
public interface IBaseInterface
{
//common props
}
public class DataType1 : IBaseInterface
{
public DataType1() { }
}
and
public class Common
{
public async Task<List<T>> Handler<T>(List<T> items) where T : IBaseInterface
{
var newList = new List<T>();
....
}
}
and call it like(just for example) :
public class Consumer
{
public void Call()
{
var param1 = new List<DataType1>();
var t = new Common().Handler<DataType1>(param1).Result;
}
}
Wrap your method inside a class which can accept T type (where T : class, new()). and add your method which accept the T - type parameter and return T-type of object.
return message can be newList.
public class Item
{
public int ID { get; set; }
public string Status { get; set; }
}
public interface IRepositoryClass
{
int ID { get; set; }
string Name { get; set; }
DateTime Retrieved { get; set; }
}
public class YourRepositoryClass<T> where T : IRepositoryClass, new()
{
public async Task<IEnumerable<T>> Handler(List<Item> items)
{
var newList= new List<T>();
foreach (var item in items)
{
newList.Add(new T
{
ID= item.ID,
Name= item.Status,
Retrieved= DateTime,
});
}
return newList; }
}
Related
I have a requirement to order several lists by the same value. But, for whatever reason, these lists contain objects of different types which share this value. Let's call it ChildID.
The simplified model code would look something like this:
public class Child
{
public string ChildID { get; set; }
}
public class Parent
{
public Child Child { get; set; }
}
public class OtherClassID
{
public int ID { get; set; }
public string ChildID { get; set; }
}
public class SomeOtherClass
{
public OtherClassID ID { get; set; }
}
So, in order to avoid code duplication, I tried this:
public interface IHasChildID
{
string GetChildID();
}
public class Child : IHasChildID
{
public string ChildID { get; set; }
public string GetChildID()
{
return ChildID;
}
}
public class Parent : IHasChildID
{
public Child Child { get; set; }
public string GetChildID()
{
return Child.ChildID;
}
}
public class OtherClassID
{
public int ID { get; set; }
public string ChildID { get; set; }
}
public class SomeOtherClass : IHasChildID
{
public OtherClassID ID { get; set; }
public string GetChildID()
{
return ID.ChildID;
}
}
And when I created a helper class with a helper method which takes an interface as a parameter, I expected it to work:
public static class ChildOrderHelper
{
public static IEnumerable<IHasChildID> OrderChildren(IEnumerable<IHasChildID> children)
{
var childrenList = children.ToList();
//do some splitting, ordering and conatenation of lists
return orderedList;
}
}
But, on every helper call I get an error:
List<Child> originalList = GetChildren(); // whatever
// some lines of code
var orderedList = ChildOrderHelper.OrderChildren(originalList).ToList(); // error
Error CS1503 Argument 1: cannot convert from
'System.Collections.Generic.List<NamespaceOne.Child>' to
'System.Collections.Generic.List<NamespaceTwo.IHasChildID>'
And so for every helper call, no matter the type.
One thing to note is that I've given an example with three distinct types that have this value and need to be ordered by it. In the project, there is probably 10 or more.
I guess there is something fundamental I don't yet understand about interface usage, but any help would be appreciated on this matter.
I'm not entirely sure what your overall use case is, but maybe it would be beneficial to make the OrderChildren method generic, as follows:
public static class ChildOrderHelper
{
public static IEnumerable<T> OrderChildren<T>(IEnumerable<T> children) where T : IHasChildID
{
var childrenList = children.ToList();
//just a simple example of what I'm guessing the method could do...
return childrenList.OrderBy(c => c.GetChildID()).ToList();
}
}
And call it as follows:
List<Child> originalList = GetChildren();
List<Child> orderedList = ChildOrderHelper.OrderChildren<Child>(originalList).ToList();
The approach can be taken like defining an interface and then implemenint that one in all the required classes or a base class that can lookup the child id.
Below is a sample of the source code.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
public class Program
{
public static void Main()
{
var parents = new List<Parent>();
parents.Add(new Parent{ChildId = "123"});
parents.Add(new Parent{ChildId = "321"});
parents.Add(new Parent{ChildId = "456"});
var result = ChildHelpers.OrderChildren(parents);
foreach(var res in result) {
Console.WriteLine(res.ChildId);
}
Console.WriteLine("Hello World");
}
}
public interface IChild {
string ChildId {get;set;}
}
public class Child : IChild {
public string Name {get;set;}
public string ChildId {get;set;}
}
public class Parent : IChild {
public Parent() {
child = new Child();
}
public Child child {get;set;}
public string ChildId {
get{
return child.ChildId;
}
set{
child.ChildId = value;
}
}
}
public class AnotherChild : IChild {
public string Description{get;set;}
public string ChildId {get;set;}
}
public static class ChildHelpers {
public static IEnumerable<IChild> OrderChildren(IEnumerable<IChild> children)
{
return children.OrderBy(c=>c.ChildId).AsEnumerable();
}
}
If you would like to playaround with this sample and see other options if required, please refer this link.
I have two objects with the same properties like this:
ObservableCollection<A> FooA
ObservableCollection<B> FooB
both model A and B have a property in common. I've created this method for update the property without create redundancy code:
public static void UpdateItemInCollection(A person, ObservableCollection<A> collection)
{
foreach (var m in collection)
{
m.Name = m.id == person.id;
}
}
But I can only pass as parameter FooA. How can I pass also FooB?
You have to use an interface or a parent (most likely abstract) class, if that property actually represents the same kind of data in both classes.
public interface INamed
{
string Name { get; }
}
public Person : INamed
{
public string Name {get; set;}
// etc.
}
public People : INamed
{
public string Name {get; set;}
// etc.
}
public static void UpdateItemInCollection(INamed person, ObservableCollection<INamed> collection)
{
foreach (var m in collection)
{
m.Name = m.id == person.id;
}
}
You can create an interface for both classes:
public interface AandB
{
string Name { get; set; }
}
Then implement it in the classes:
public interface AandB
{
string Name { get; set; }
}
public class A : AandB
{
public string Name { get; set; }
public string id { get; set; }
}
class B : AandB
{
public string Name { get; set; }
public string id { get; set; }
}
Modify your method to get the interface instead of the class:
public static void UpdateItemInCollection(AandB person, ObservableCollection<AandB> collection)
{
foreach (var m in collection)
{
m.Name = "whatever";
}
}
The collections must be the interface type:
ObservableCollection<AandB> FooA;
ObservableCollection<AandB> FooB;
And finally,you can call the method with both classes:
FooA = new ObservableCollection<AandB>();
A objA = new A();
objA.id = "1";
objA.Name = "test";
FooA.Add(objA);
FooB = new ObservableCollection<AandB>();
B objB = new B();
objB.id = "1";
objB.Name = "test";
FooB.Add(objB);
UpdateItemInCollection(objA, FooA);
UpdateItemInCollection(objB, FooB);
I have the following code which i would expect to return the properties within the generic type.
var newType = new T();
Type t = newType.GetType();
var prop = t.GetProperties();
prop has 0 properties and i cant understand why, when inspecting the type object at debug it is showing the correct object. The object im using as the generic.
public class SOPOH
{
public String OHDELF { get; set; }
public Decimal OHORDR { get; set; }
public String OHSTAT { get; set; }
public String OHSUSP { get; set; }
public Decimal OHODDT { get; set; }
public String OHCUSN { get; set; }
public String OHCSUB { get; set; }
}
prop returns {System.Reflection.PropertyInfo[0]}
t returns {Name = "SOPOH" FullName = "AS400_Library.Repositorys.CHGDGADV.SOPOH"}
The Generic class:
public class Repository<T> : IRepository<T> where T : new()
{
public List<T> GetAll(Settings settings)
{
var returned = new List<T>();
var newType = new T();
Type t = newType.GetType();
var prop = t.GetProperties();
Console.WriteLine(prop.Length);
return returned;
}
}
The Interface:
public interface IRepository<T> where T : new()
{
List<T> GetAll(Settings settings);
}
The implementation of the repository:
public class SOPOH : Repository<SOPOH>
{
public SOPOH()
{
}
}
The call to the code:
var t = new AS400_Library.Repositorys.CHGDGADV.SOPOH();
var values = t.GetAll(new Settings());
Currently I have quite many classes (5) that have just 2 properties but have different names for different purposes:
public class Class1
{
public Class1()
{
}
public string Id { get; set; }
public string Value { get; set; }
}
public class Class2
{
public Class2()
{
}
public string Id { get; set; }
public string Value { get; set; }
}
........
public class Class5
{
public Class5()
{
}
public string Id { get; set; }
public string Value { get; set; }
}
Then I have for each of those classes a method that will return a List<Class>.
public static List<Class1> GetClass1()
{
Dictionary<string, string> s = GetSomeResults1();
List<Class1> _s = new List<Class1>();
foreach (var item in s)
{
Class1 c = new Class1();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
public static List<Class2> GetClass2()
{
Dictionary<string, string> s = GetSomeResults2();
List<Class2> _s = new List<Class2>();
foreach (var item in s)
{
Class2 c = new Class2();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
......
public static List<Class5> GetClass5()
{
Dictionary<string, string> s = GetSomeResults5();
List<Class5> _s = new List<Class5>();
foreach (var item in s)
{
Class5 c = new Class5();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
Any advise how can I better make this code?
Use a base class to put the shared properties and functions in:
public class BaseClass
{
public string Id { get; set; }
public string Value { get; set; }
// shared properties and methods
}
public class Class1 : BaseClass
{
// own properties and methods
}
public class Class2 : BaseClass
{
// own properties and methods
}
I will suggest create a seperate class for
public string Id { get; set; }
public string Value { get; set; }
and call inside class.
You can use class inheritance and put common parts of code to a base class like this:
/// <summary>
/// Base class
/// </summary>
public class BaseClass
{
public BaseClass()
{
}
public string Id { get; set; }
public string Value { get; set; }
public virtual List<BaseClass> GetClass();
protected List<TClass> GetList<TClass> (Dictionary<string, string> s) where TClass : BaseClass, new() {
List<TClass> _s = new List<TClass>();
foreach (var item in s)
{
TClass c = new TClass();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
}
public class Class1 : BaseClass
{
public override List<Class1> GetClass() {
Dictionary<string, string> s = GetSomeResults1();
return GetList<Class1>(s);
}
}
You can use a base class:
public abstract class BaseClass{
public string Id { get; set; }
public string Value { get; set; }
}
public class Class1 : BaseClass
{
public Class1()
{
}
}
public class Class2: BaseClass
{
public Class2()
{
}
}
Now you can make a generic method which returns the interface of List<T> where T is of type BaseClass
public static List<T> GetClass<T>(Func<Dictionary<string, string> func) where T : BaseClass, new()
{
Dictionary<string, string> s = func();
List<T> _s = new List<T>();
foreach (var item in s)
{
T c = new T();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
Then call:
List<Class2> class2list = GetClass<Class2>(GetSomeResults2);
Patrick Hofman's answer is right, but i'd also add that using a BaseClass would allow you to reduce the amount of code working with your classes.
public static List<T> GetClassList() where T:BaseClass
{
Dictionary<string, string> s = GetSomeResults<T>();
List<T> _s = new List<T>();
foreach (var item in s)
{
T c = new T();
c.Id = item.Key;
c.Value = item.Value;
_s.Add(c);
}
return _s;
}
Changing just this function is not enough though, you also need a way to implement the GetSomeResults() methods. I don't really know what your logic looks like and how different these methods are, but smth like this can help in the worst case when methods are completely different.
public static Dictionary<string, string> GetSomeResults<T>() where T : BaseClass
{
if (T == typeof(Class1))
{
return GetSomeResults1();
}
else if (T == typeof(Class2))
{
//You got it..
}
}
I have many similar EF5 entities for reference data. For example:
ConsultationType entity
public class ConsultationType
{
public ConsultationType()
{
this.Appeals = new HashSet<Appeal>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Appeal> Appeals { get; set; }
}
LawBranch entity
public class LawBranch
{
public LawBranch()
{
this.Appeals = new HashSet<Appeal>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<Appeal> Appeals { get; set; }
}
DbSet's in DB context
public DbSet<LawBranch> LawBranches { get; set; }
public DbSet<ConsultationType> ConsultationTypes { get; set; }
As you see these entities have similar properties Id and Title.
The actual problem
I need a function that fetches data from database and puts it into list. Then the function inserts predefined object as a first element of this list.
My predefined object:
private class PredefinedReferenceItem
{
public int Id { get; set; }
public string Title { get; set; }
public PredefinedReferenceItem()
{
this.Id = -1;
this.Title = "some text";
}
}
My wrong solution:
Firstly, I created interface IReference that describes reference entity
public interface IReference
{
int Id { get; set; }
string Title { get; set; }
}
Secondly, my reference entities realize this interface
public class ConsultationType : IReference { ... }
public class LawBranch: IReference { ... }
Thirdly, I created the function
public IList<IReference> GetReferenceWithPredefinedItem<T>(DbSet<IReference> dbset)
{
var data = from a in dbset
orderby a.Title
select a;
var list = data.ToList();
list.Insert(0, new PredefinedReferenceItem());
return list;
}
But the function doesn't work in my viewmodel:
return GetReferenceWithPredefinedItem(dbContext.ConsultationTypes);
Error message in VS2012:
The type arguments for method 'Mjc.Client.ViewModels.ViewModelBase.GetReferenceWithPredefinedItem<T>(System.Data.Entity.DbSet<Mjc.Foundation.IReference>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
Please help me to find an error or specify the right direction.
You new to change the GetReferenceWithPredefinedItem to use generics with IReference constraint on generic type T, the method should look like:
public IList<T> GetReferenceWithPredefinedItem<T>(DbSet<T> dbset) where T:IReference
{
var data = from a in dbset
orderby a.Title
select a;
var list = data.ToList();
list.Insert(0, new PredefinedReferenceItem());
return list;
}
alexandr-mihalciuc provided right solution. My addition to resolve type reference error:
Final solution:
public List<TEntity> GetReferenceWithPredefinedItem<TEntity>(DbSet<TEntity> dbset) where TEntity : class, new(), IReference
{
var data = from a in dbset
orderby a.Title
select a;
var list = data.ToList();
list.Insert(0, new TEntity() { Id = -1, Title ="aefaef" });
return list;
}