I have 2 classes that look exactly the same but reside in different namespaces. One property of the nested class is an array of itself, which allows property nesting/recursion (sort of like a command pattern)
I am trying to convert/cast the class from one namespace to the class in another namespace. I have the below code:
namespace Common.Class
{
public class Root
{
public string Key { get; set; }
public Child[] Children { get; set; }
public class Child
{
public string Content { get; set; }
public Child[] RecursionChild { get; set; }
}
}
}
namespace Uncommon.Class
{
class Root
{
public string Key { get; set; }
public Child[] Children { get; set; }
public class Child
{
public string Content { get; set; }
public Child RecursionChild { get; set; }
}
}
}
The main program
static void Main(string[] args)
{
var commonRoot = new Common.Class.Root
{
Key = "1234-lkij-125l-123o-123s",
Children = new Common.Class.Root.Child[]
{
new Common.Class.Root.Child
{
Content = "Level 1 content",
RecursionChild = new Common.Class.Root.Child[] { }
}
}
};
var uncommonRoot = new Uncommon.Class.Root
{
Key = commonRoot.Key,
Children = commonRoot.Children // here I get error: Cannot implicitly convert type 'Common.Class.Root.Child[]' to 'Uncommon.Class.Root.Child[]'
};
}
You need to convert the children too.
Because you've got that recursive child, you can't pull this off with just anonymous functions, because the function has to be able to call itself, and you need a name for that. So we need to introduce a local function with a real name, e.g. Converter.
Uncommon.Root.Child Converter(Common.Root.Child source) => new Uncommon.Root.Child
{
Content = source.Content,
RecursiveChild = Converter(source.ResursiveChild)
};
var uncommonRoot = new Uncommon.Class.Root
{
Key = commonRoot.Key,
Children = commonRoot.Children.Select(Converter).ToArray();
};
Related
I have the following class which is populated after de-serializing a JSON string:
public class Doors
{
public List<Door> doors { get; set; }
}
public class Door
{
public int id { get; set; }
public string name { get; set; }
public bool elevator { get; set; }
}
JSON string:
var result = JsonConvert.DeserializeObject<Doors>(response.Content);
// "{\"doors\":[{\"id\":1,\"name\":\"Main Door\",\"elevator\":false},{\"id\":2,\"name\":\"Back Door\",\"elevator\":false}]}"
The data maps to my class fine, I'm then trying to pass the class data to another class:
public class WS4APIResult
{
public List<Door> doors { get; set; } = new List<Door>();
}
public class Door
{
public int id { get; set; }
public string name { get; set; }
public bool elevator { get; set; }
}
return new WS4APIResult() {
doors = result.doors
}
With the following error: any ideas please?
Cannot implicitly convert type 'System.Collections.Generic.List<WS4PortalApi.Models.Door>' to 'System.Collections.Generic.List<WS4PortalApi.Domain.Door>'
The two c#-Files refer to different classes if you type Door. You need to implement a conversion between WS4PortalApi.Models.Door and WS4PortalApi.Domain.Door.
Like:
public static WS4PortalApi.Domain.Door DoorConvert(WS4PortalApi.Models.Door door)
then you can use linq to generate a new List
doors = result.doors
.Select(d => DoorConvert(d))
.ToList();
You have to map the properties of your domain object to those of the model.
I normally create a method for this like:
var doors = new List<Model.Door>();
foreach(door in result.doors)
{
var doorModel = new Model.Door
{
id = door.id,
name = door.name,
elevator = door.elevator
};
doors.Add(doorModel);
}
return doors;
Or you can use a library like automapper.
I'm having some trouble mapping an object with multiple layers of properties to an object with a single layer of properties. Here's an example:
My destination class
public class Part
{
public string Name { get; set; }
public string PartNumber { get; set; }
public string Position { get; set; }
public IList<Part> ReplacedBy { get; set; } = new List<Part>();
}
My source classes
public class PartType
{
public string PartNumber { get; set; }
public PartInformationType Part { get; set; }
}
public class PartInformationType
{
public string Position { get; set; }
public string Name { get; set; }
public IList<PartType> ReplacedBy { get; set; } = new List<PartType>();
}
Note that the real objects have ALOT more properties in each layer so it would be a hassle to do a ForMember() on each affected property. Is there any automated way to do this for me?
Expected result:
This is giving me the expected result but only for one generation of parts, say that each replacedBy part is replaced by another part for 10 generations, that quickly becomes unmanageable
var part = Mapper.DynamicMap<Part>(result);
part.ReplacedBy = new List<ReplacementPart>();
foreach (var partType in result.ReplacedBy)
{
var replacementPart = Mapper.DynamicMap<ReplacementPart(partType.Part);
replacementPart.Name= partType.Name;
replacementPart.Position= partType.Position;
part.ReplacedBy.Add(replacementPart);
}
This is an interesting problem, and I happen to have solved a very similar one recently in one of my projects so hopefully my answer will suit your needs as well or at least get you going on the right track. I've adjusted the sample code somewhat to your case.
My destination model class (pretty much same as yours):
public class PartModel
{
public string Name { get; set; }
public string PartNumber { get; set; }
public string Position { get; set; }
public List<PartModel> ReplacedBy { get; set; }
}
My two source classes (also pretty much same as yours)
public class PartEntity
{
public string PartNumber { get; set; }
public PartEntityInformation PartEntityInformation { get; set; }
}
public class PartEntityInformation
{
public string Position { get; set; }
public string Name { get; set; }
public List<PartEntity> ReplacedBy { get; set; }
}
I have defined a static EntityMap with the configurations for my two mappings. As I have mentioned in the comments of your question - I am not specifying any particular member mapping config as Automapper will just map by convention because the property names match between my source and destination objects.
public static class EntityMap
{
public static IMapper EntityMapper { get; set; }
static EntityMap()
{
EntityMapper = new MapperConfiguration(config =>
{
config.CreateMap<PartEntity, PartModel>();
config.CreateMap<PartEntityInformation, PartModel>();
}).CreateMapper();
}
}
You can use EntityMap like below. Nothing special here, it will just yield me the base model where only PartNumber property is mapped.
var rootPart = GetPart();
var rootPartModel = EntityMap.EntityMapper.Map<PartModel>(rootPart);
In order to get the nested mappings for your ReplacedBy parts, you can use recursion (this is how I solved this nested mapping requirement in my project, there may be better solutions). In this method, I recursively map the nested child objects to their destination objects because the initial mapping will give me the number of items that there is in the nested ReplacedBy list.
public static void MapRecursively(PartModel partModel, PartEntity partEntity)
{
EntityMap.EntityMapper.Map(partEntity.PartEntityInformation, partModel);
if (partEntity.PartEntityInformation.ReplacedBy == null
|| partEntity.PartEntityInformation.ReplacedBy.Count == 0) return;
for (var i = 0; i < partModel.ReplacedBy.Count; i++)
{
MapRecursively(partModel.ReplacedBy[i], partEntity.PartEntityInformation.ReplacedBy[i]);
}
}
So you can now just use the rootPart and rootPartModel with this recursive method to map out of the rest of your nested objects.
MapRecursively(rootPartModel, rootPart);
This should work out of the box, I have provided the GetRootPart() method specification below as it is just the sample data I have used.
private static PartEntity GetPart()
{
var partEntityInfo = new PartEntityInformation
{
Name = "SomeName",
Position = "2",
ReplacedBy = new List<PartEntity>
{
new PartEntity
{
PartNumber = "22",
PartEntityInformation = new PartEntityInformation
{
Name = "SomeSubName"
}
},
new PartEntity
{
PartNumber = "33",
PartEntityInformation = new PartEntityInformation
{
Name = "33SubName",
Position = "33SubPosition",
ReplacedBy = new List<PartEntity>
{
new PartEntity
{
PartNumber = "444",
PartEntityInformation = new PartEntityInformation
{
Name = "444SubSubname"
}
}
}
}
}
}
};
var part = new PartEntity
{
PartNumber = "1",
PartEntityInformation = partEntityInfo
};
return part;
}
I wonder if there's any way to match the names in a list with the elements in a class:
I have a class:
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
and a List: List<exampleClass> EnfSist
So that's the way the list is made. Now I would like to know how to match or identify the string inside "name" from my list. To match this class:
tbl_sistematicas b = new tbl_sistematicas
{
ap_enf_id_enfermedad = Convert.ToInt32(EnfSist[0].value),
ap_pac_inicio = Convert.ToInt32(EnfSist[1].value),
ap_pac_inicio_periodo = Convert.ToInt32(2].value),
ap_pac_duracion = Convert.ToInt32(EnfSist[3].value),
ap_pac_duracion_periodo = Convert.ToInt32(EnfSist[4].value),
ap_pac_tratamiento = EnfSist[5].value
};
Once being able to match the same names I won't have to specify each index of every element in the list. The elements in the list have the same name as in the table. Not all elements of the class are being used.
I have something like this: tbl_sistematicas bh = EnfSist.FindAll(x => x.name == bh.?????? );
If I understand the question, you can do this using something like automapper or ValueInjector
An example using ValueInjector
void Main()
{
List<exampleClass> EnfSist = new List<exampleClass>();
EnfSist.Add(new exampleClass { name = "ap_enf_id_enfermedad", value = "12" });
EnfSist.Add(new exampleClass { name = "apap_pac_inicio" , value = "34" });
// etc
tbl_sistematicas b = new tbl_sistematicas();
b.InjectFrom<MyInjection>(EnfSist);
}
public class MyInjection : KnownSourceValueInjection<List<exampleClass>>
{
protected override void Inject(List<exampleClass> source, object target)
{
foreach(var entry in source)
{
var property = target.GetProps().GetByName(entry.name, true);
if (property != null)
property.SetValue(target, Convert.ChangeType(entry.value, property.PropertyType));
}
}
}
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
public class tbl_sistematicas
{
public int ap_enf_id_enfermedad { get; set; }
public int apap_pac_inicio { get; set; }
public int ap_pac_inicio_periodo { get; set; }
public int ap_pac_duracion { get; set; }
public int ap_pac_duracion_periodo { get; set; }
public string ap_pac_tratamiento { get; set; }
}
Note, this will throw an exception if the value can not be converted to an int
My First Model in WCF
public class One
{
public string A { get; set; }
public string B { get; set; }
}
My Second
public class Two : One
{
public string C { get; set; }
}
Now I have Value for the properties of Model Two like this
Two obj = new Two()
{
A="ww",
B="WWW",
C="EE"
};
One obj1 = new One();
Now i want to copy my obj object value to obj1.
But i need to skip the third value while copying in first object ..How To do it?
You can create a copy constructor for One:
public class One
{
public One(One other)
{
A = other.A;
B = other.B;
}
public string A { get; set; }
public string B { get; set; }
}
And use it like this:
Two two = new Two
{
A="ww",
B="WWW",
C="EE"
};
One one = new One(two);
I currently have three Model classes:
public class MarketReport
{
public MarketReportAbbrStores LISTOFSTORESUMMARY {get; set;}
}
public class MarketReportAbbrStores : List<AbbrStore>
{
public AbbrStore abbrStore { get; set; }
}
public class AbbrStore
{
public string StoreName { get; set; }
public int MemberCount { get; set; }
public int LeaderCount { get; set; }
public int ActivistCount { get; set; }
}
Now, I have no idea if I am doing the above correctly, but I want to populate the list within the MarketReport
foreach (var store in stores)
{
AbbrStore abbrstore = new AbbrStore();
abbrstore.StoreName = store;
marketInformation.LISTOFSTORESUMMARY.Add(abbrstore);
//ERROR: Object reference not set to an instance of an object.
}
Several things wrong here:
Your Leaders type is a List of itself - this shouldn't be a collection type because it's describing a single entity, so just Leader
leaderlist should use PascalCase - Leaders
leaderlist is an instance property, so you would need to instantiate a MarketReport to start to populate that list
leaderlist should be a List<Leader> if you don't have a collection type defined (see 1)
List<T> has an Add method which you should use to add new instances of Leader
You will need to instantiate a new list and assign it to the Leaders property before you can start adding to it
Suggested changes:
public class Leader
{
public string Name { get; set; }
public string Precinct { get; set; }
}
public class MarketReport
{
public List<Leader> Leaders { get; set }
}
this.Leaders = new List<Leader>();
foreach (var store in stores)
{
var leader = new Leader { ... };
this.Leaders.Add(leader);
}