Objects with same properties as unic parameter? - c#

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

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

AutoMapper c# runtime mapping depending on an object property

I would like to know, how could I, with AutoMapper, Map one Dto to multiple entities.
Lemme explain.
I've got one Dto, with an enum to describe its type (to avoid having multiple dtos)
Depending on that enum (RelationType here), I would like to map it to the correct Model (Entity, what ever, it's another object that I use in database).
public class BCardDto : IMappedDto
{
public long Id { get; set; }
public BCardRelationType RelationType { get; set; }
public long RelationId { get; set; }
}
Here are is my Model base:
public class BCardModel : IMappedDto
{
public long Id { get; set; }
}
And here the derived model :
public class CardBCardModel : BCardModel
{
// ormlite, ignore that
[Reference]
public CardModel Card { get; set; }
[ForeignKey(typeof(CardModel), ForeignKeyName = "fk_bcard_card")]
public long RelationId { get; set; }
}
How do I map my Dto to the correct Model depending on the enum i've given ?
(I don't wanna use Mapper.Map everywhere but I wanna let mapper do the runtime mapping job)
Here is how I do it for the Model -> Dto
cfg.CreateMap<CardBCardModel, BCardDto>()
.ForMember(s => s.RelationType, expression => expression.UseValue(BCardRelationType.Card))
.IncludeBase<BCardModel, BCardDto>();
Tell me if I do something wrong and explain me why please :)
Thanks by advance,
Blowa.
Let's say you have a setup wherein there is a base class and 2 classes which derive the base class:
public class ModelBase
{
public string Name { get; set; }
}
public class ModelOne : ModelBase { }
public class ModelTwo : ModelBase { }
Let's also say you have a DTO with an enum as below:
public class ModelDto
{
public string Name { get; set; }
public ModelType ModelType { get; set; }
}
public enum ModelType
{
One = 1,
Two = 2
}
So now the task is: How do I map the ModelDto to either ModelOne or ModelTwo depending on the value in ModelDto.ModelType property?
Here is how:
Mapper.Initialize(cfg => cfg.CreateMap<ModelDto, ModelBase>().ConstructUsing(x =>
{
switch (x.ModelType)
{
case ModelType.One:
return new ModelOne { Name = x.Name };
case ModelType.Two:
return new ModelTwo { Name = x.Name };
default:
throw new InvalidOperationException("Unknown ModelType...");
}
}));
Usage
var dto1 = new ModelDto { ModelType = ModelType.One, Name = "ModelOne" };
var dto2 = new ModelDto { ModelType = ModelType.Two, Name = "ModelTwo" };
var one = Mapper.Map<ModelBase>(dto1);
var two = Mapper.Map<ModelBase>(dto2);
Another way to do the mapping is by using dynamic:
public class PersonDto
{
public string Name { get; set; }
}
public class StudentDto : PersonDto
{
public int studentNumber { get; set; }
}
public class EmployeDto : PersonDto
{
public string EmployeId { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public class Student : Person
{
public int StudentNumber { get; set; }
}
public class Employe : Person
{
public string EmployeId { get; set; }
}
Create Map by using:
Mapper.CreateMap<StudentDto, Student>();
Mapper.CreateMap<EmployeDto, Employe>();
Do the Mapping by:
try
{
var student = MapPerson((dynamic) studentDto);
var employe = MapPerson((dynamic) employeDto);
}
catch
{
throw new InvalidOperationException("Unknown ModelType...");
}
And define two Methods
public static Student MapPerson(StudentDto studentDto)
{
return Mapper.Map<StudentDto, Student>(studentDto);
}
public static Employe MapPerson(EmployeDto employeDto)
{
return Mapper.Map<EmployeDto, Employe>(employeDto);
}
The benefit is that you don't need a key and avoid the switch statement

Sending List of objects in c# web service

I have the following two objects:
public class Dog
{
public string Name {get;set;}
public int Age {get;set;}
}
public class Person
{
public string Name {get;set;}
public string City {get;set;}
public string ID {get;set;}
}
Now, in the server side, I build a mix List of Person and Dog, and I would like to return this List to the client via web-service (asmx).
The order is important, and eventually my list will hold more types.
How can I return a list of mixed object in web-service?
Thank you.
I think you should create new class that encapsulate your many classes
public class Dog : MyClass
{
public string Name {get;set;}
public int Age {get;set;}
}
public class Person : MyClass
{
public string Name {get;set;}
public string City {get;set;}
public string ID {get;set;}
}
public class NewClass
{
public enum OBJType {
Dog,Person
} // like a constant for specific object type
public Dog D_Dog { get; set; }
public Person D_Person { get; set; }
public OBJType Type { get; set; }
public int seq { get; set; }
}
Then it should be use like this
//At Server
List<NewClass> newList = new List<NewClass>();
NewClass Item1 = new NewClass();
Item1.D_Dog = new Dog() { Name = "Woof", Age = 3 };
Item1.seq = 1;
Item1.Type = NewClass.OBJType.Dog;
newList.Add(Item1);
NewClass Item2 = new NewClass();
Item2.D_Person = new Person() { Name = "John", City = "TPP" , ID =111 };
Item2.seq = 2;
Item2.Type = NewClass.OBJType.Person;
newList.Add(Item2);
//At Client
List<NewClass> newList = //..get form webservice
foreach (var Item in newList)
{
if (Item.Type == NewClass.OBJType.Dog)
{
// using Item.D_Dog;
}
else {
// using Item.D_Person
}
}
Not a pro at C# so excuse if its not the most efficient.
1st class ie Person.cs
public class Person : MyClass
{
public string Name { get; set; }
public string City { get; set; }
public string ID { get; set; }
}
2nd Class ie Dog.cs
public class Dog : MyClass
{
public string Name { get; set; }
public int Age { get; set; }
}
The inherited class ie MyClass.cs
public class MyClass
{
public string Type { get; set; }
}
Notice I have added a field Type to differentiate between objects in the program consuming the webservice. You can improve this with enums for type.
The Example function to return the data.
public List<MyClass> returnData()
{
List<MyClass> returningdata = new List<MyClass>();
Person pers = new Person();
pers.City = "NELSPRUIT";
pers.Name = "TED";
pers.ID = "5502226585665";
pers.Type = "PERSON";
returningdata.Add(pers);
Dog doggy = new Dog();
doggy.Name = "Tiny";
doggy.Age = 2;
doggy.Type = "DOG";
returningdata.Add(doggy);
return returningdata;
}
Hope this is what you wanted.

Nested objects to one object using Automapper

Have a requirement to map name (Class A) and phone number (Class B) to Class C which has both Name and PhoneNumber. A person (name) can have more than one phone numbers.
public class A
{
public int ID { get; set; }
public string Name { get; set; }
public virtual IList<B> B { get; set; }
}
public class B
{
public int A_ID { get; set; }
public string PhoneNumber { get; set; }
}
public class C
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
Getting A class (which has B) details from the database and it needs to be mapped to Class C.
public class Activity
{
public IList<C> GetContacts(string name)
{
using (ModelEntities ctx = new ModelEntities())
{
Mapper.CreateMap<A, C>();
Mapper.CreateMap<B, C>();
var result =
ctx.A.SingleOrDefault(ss => ss.Name == name);
}
}
}
Can anyone help me to map using Automapper?
Thanks
AutoMapper cannot map from a single instances to multiple instances. It either must be instance to instance or enumerable to enumerable. The best path forward I can see is to simply map your IList<B> to IList<C> and then back-fill the Name property. Something along the lines of:
var c = Mapper.Map<IList<C>>(a.B);
c.ToList().ForEach(m => m.Name = a.Name);
However, unless your mapping is hella more complex than this, AutoMapper is overkill. You could simply do:
var c = a.B.Select(b => new C { Name = a.Name, PhoneNumber = b.PhoneNumber });

Passing dynamic type, iterating fields and replacing values

I have 3/4 different models that each contain their own nested model. I need a way of iterating all fields, including those of the nested model and do a string replace (although not all fields are strings).
My initial idea was to write a method which allows for a 'dynamic' type to be passed.
Input model:
Name = Joe
Surname = Smith
Address = new ClientAddress
{
Line1: Item A
Line2: mistake
Line3: mistake
}
My example method:
MyMethod (dynamic passInModel)
{
....
passInModel.Replace("mistake","correction");
return passInModel;
}
Output:
Name = Joe
Surname = Smith
Address = new ClientAddress
{
Line1: Item A
Line2: correction
Line3: correction
}
Despite trying various ways of doing it I've not had any success in writing something that does the job.
You could write a method that accepts an object and use reflection to iterate through all the fields, but you're getting into messy territory there. In my opinion, even using dynamic here is messy.
Consider using a modified visitor pattern here. If your domain objects look like this:
public class ModelBase
{
}
public class MyModel1 : ModelBase
{
public string Name { get; set; }
public string Surname { get; set; }
public ClientAddress Address { get; set; }
}
public class MyModel2 : ModelBase
{
public string CompanyName { get; set; }
public string Region { get; set; }
public CompanyAddress Address { get; set; }
}
public class ClientAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}
public class CompanyAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public List<string> AdditionalLines { get; set; }
}
Write a visitor that takes an abstract ModelBase and dispatches the correct type-safe visitor:
public class ModelFixVisitor
{
public ModelBase Visit(ModelBase model)
{
var asModel1 = model as MyModel1;
if (asModel1 != null)
{
return new Model1FixVisitor().Visit(asModel1);
}
var asModel2 = model as MyModel2;
if (asModel2 != null)
{
return new Model2FixVisitor().Visit(asModel2);
}
throw new NotImplementedException("Unknown model type.");
}
}
Then write a simple class for each type (and subtype) you need to visit:
public class Model1FixVisitor
{
public MyModel1 Visit(MyModel1 model)
{
model.Name = new StringFixVisitor().Visit(model.Name);
model.Surname = new StringFixVisitor().Visit(model.Surname);
model.Address = new ClientAddressFixVisitor().Visit(model.Address);
return model;
}
}
public class Model2FixVisitor
{
public MyModel2 Visit(MyModel2 model)
{
model.CompanyName = new StringFixVisitor().Visit(model.CompanyName);
model.Region = new StringFixVisitor().Visit(model.Region);
model.Address = new CompanyAddressFixVisitor().Visit(model.Address);
return model;
}
}
public class ClientAddressFixVisitor
{
public ClientAddress Visit(ClientAddress address)
{
address.Line1 = new StringFixVisitor().Visit(address.Line1);
address.Line2 = new StringFixVisitor().Visit(address.Line2);
address.Line3 = new StringFixVisitor().Visit(address.Line3);
return address;
}
}
public class CompanyAddressFixVisitor
{
public CompanyAddress Visit(CompanyAddress address)
{
address.Line1 = new StringFixVisitor().Visit(address.Line1);
address.Line2 = new StringFixVisitor().Visit(address.Line2);
address.AdditionalLines = new StringListFixVisitor().Visit(address.AdditionalLines);
return address;
}
}
public class StringFixVisitor
{
public string Visit(string element)
{
return element.Replace("mistake", "correction");
}
}
public class StringListFixVisitor
{
public List<string> Visit(List<string> elements)
{
return elements
.Select(x => new StringFixVisitor().Visit(x))
.ToList();
}
}
I'm sure the code could be refactored and optimized, but it should express the general idea.
What I like about this type of solution is that it breaks the problem down into small, manageable chunks: How do I fix a string? How do I fix a ClientAddress?
Fixing entire models then becomes simple composition of these smaller classes. It's a little more verbose, but you get to keep type safety, and don't have to mess with reflection.
You can use the power of .Net reflection to solve this.
I created a class called DeepStringReplacer. Using reflection it iterates through object properties and if the type is string, perform string replace.
Check the code below:
public class DeepStringReplacer
{
public object Replace(object input, string oldValue, string newValue)
{
if (input is string)
{
return input.ToString().Replace(oldValue, newValue);
}
var fields = input.GetType().GetProperties();
foreach (var field in fields)
{
var fieldValue = field.GetValue(input);
field.SetValue(input, Replace(fieldValue, oldValue, newValue));
}
return input;
}
}
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public ClientAddress Address { get; set; }
}
public class ClientAddress
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
}

Categories