Reduce code duplicates - c#

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

Related

How to make this method generic?

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

Get class property depending on generic interface

Lets say i have this:
public interface IMyInterface<T>
{
}
public class MyClass
{
public IMyInterface<Foo> Foos {get; set;}
public IMyInterface<Bar> Bars {get; set;}
}
I want to have a method like this one
MyClass.Interfaces<T>()
Which will return MyClass.Foos or MyClass.Bars Depending on T value.
How i do that?
It's very similar on how EF works.
It requires some plumbing and casting, but you could do that with a dictionary:
public interface IMyInterface<T> {
}
public class Foo { }
public class Bar { }
public class MyClass {
Dictionary<Type, object> myInterfaces = new Dictionary<Type, object>();
public IMyInterface<Foo> Foos {
get { return (IMyInterface<Foo>)myInterfaces[typeof(Foo)]; }
set { myInterfaces[typeof(Foo)] = value; }
}
public IMyInterface<Bar> Bars {
get { return (IMyInterface<Bar>)myInterfaces[typeof(Bar)]; }
set { myInterfaces[typeof(Bar)] = value; }
}
public IMyInterface<T> Interfaces<T>() {
return (IMyInterface<T>)myInterfaces[typeof(T)];
}
}
public class MyClass
{
public IMyInterface<Foo> Foos { get; set; }
public IMyInterface<Bar> Bars { get; set; }
public IMyInterface<T> Interfaces<T>()
{
var property = GetType().GetProperties()
.Where(x => x.PropertyType.Name.StartsWith("IMyInterface")
&&
x.PropertyType.GenericTypeArguments.Contains(typeof(T)))
.FirstOrDefault();
if (property != null)
return (IMyInterface<T>)property.GetValue(this);
return null;
}
}

Objects with same properties as unic parameter?

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);

C# Generic types GetProperties() returns 0 properties

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());

Expendable complex types inside complex types in any collection (Property grid)

Hello I want to have a expandable collection of complex types which are inside of other complex type.
How I want to do this:
private static void SetExpandableAttrForType(Type type)
{
var props = type.GetProperties();
foreach (var prop in props.Where(x =>!x.PropertyType.IsSimpleType()&& x.CanWrite))
{
SetExpandableAttrForType(prop.PropertyType);
}
TypeDescriptor.AddAttributes(type, new TypeConverterAttribute(typeof (ExpandableObjectConverter)));
}
and then
SetExpandableAttrForType(arrayInstance.GetType().GetElementType());
Test model:
public class Class1
{
public Class2 Class2Inclass1 { get; set; }
public Class2[] Class2Array { get; set; }
}
public class Class2
{
public Class3 Class3Inclass2 { get; set; }
public string Class2String { get; set; }
public string Class2String2 { get; set; }
}
public class Class3
{
public Class4 Class4Inclass3 { get; set; }
public string Class3String { get; set; }
public int Class3Int { get; set; }
}
public class Class4
{
public int Class4Int { get; set; }
public DateTime Class4Datetime { get; set; }
}
It works fine for types but not for collection of types.
The great thing about programming is this, when u tell somebody about the problem, often you start to look at it from another angle. The problem was that I need instance of this nested complex type. CellValueChanged event give me type and then I just need to create instance of it.
private void propertyGridControl1_CellValueChanged(object sender, CellValueChangedEventArgs e)
{
var changedObject = e.Value;
if (changedObject != null)
{
if (changedObject.GetType().IsArray || changedObject.GetType().IsGenericList())
{
var collectionItems = changedObject as IEnumerable;
if (collectionItems != null)
foreach (var item in collectionItems)
{
SetValueOfCollectionComplexObject(item);
}
}
}
}
public void SetValueOfCollectionComplexObject(object item)
{
var complexProps = item.GetType().GetProperties().Where(x => !x.PropertyType.IsSimpleType());
foreach (var prop in complexProps)
{
if (prop.GetValue(item) == null)
{
prop.SetValue(item, Activator.CreateInstance(prop.PropertyType));
SetValueOfCollectionComplexObject(prop.GetValue(item));
}
}
}

Categories