Clean way to Compare / Copy between Similar Classes - c#

We have two classes that have the exact same public accessors (and many of them) but are from different areas in the object hierarchy; we have a need to copy and compare between these two objects. We could manually write a copy constructor and a comparison operator which compares the values of the same-named accessors, but it seems as though there's got to be a better way to do this using reflection and LINQ.
Example: we have class ClassA which has 70 accessors; we also have class ClassB which has 70 accessors, which are defined to be the same name and type as ClassA's accessors.
public class ClassA
{
int OneInt {get; set;}
int TwoInt {get; set;}
...
string OneString {get; set;}
string AnotherString {get; set;}
}
public class ClassB
{
int OneInt {get; set;}
int TwoInt {get; set;}
...
string OneString {get; set}
string AnotherString {get; set;}
}
What I'd like is a simple way of using reflection to discover all of the public accessors of ClassA, and use those names to set the values of the respective accessor on ClassB to the value of the accessor on ClassA. Roughly, in psuedocode:
foreach (string accName in ClassA.Accessors[])
BInstance.Accessors[accName].Value = AInstance.Accessors[accName].Value;
And, of course, the same thing could be used for testing equality between the two classes. My knowledge of C# reflection and LINQ is not good enough to know how to get this done, but I'd swear it's something relatively simple.

How about using AutoMapper:
Mapper.CreateMap<ClassA, ClassB>();
and then:
ClassA classA = ...
ClassB classB = Mapper.Map<ClassA, ClassB>(classA);
It's basically an implementation of your pseudo-code.

your rough pseudocode is somewhat accurate. Let me clean it up a little:
foreach (var propertyA in typeof(ClassA).GetProperties())
{
var propertyB = typeof(ClassB).GetProperty(propertyA.Name);
var valueA = propertyA.GetValue(objectA, null);
propertyB.SetValue(objectB, valueA, null);
}
Obviously, this doesn't do error checking, and stuff like that, but it should do the job.
You could do it in Linq, but I don't think it would be cleaner.

Related

Best way to filter over object's property by value

class Sample
{
public type1 Prop1 {get; set;}
public type2 Prop1 {get; set;}
public type3 Prop1 {get; set;}
.
.
.
.
.
public typen Propn {get; set;}
}
The problem is as follows:
Say I have a list of Sample objects. I have to provide funcionality to filter objects over a specific property by a specific value.
The method should be as follows:
List<Sample> filter(string propertyName, string value)
{
...
}
The intuitive approach I came up with is to switch case on propertyName, try to parse the input value to its real type
and then make the comparison. What disturbs me is that if the object has many properties, this solutions results with
logic duplication. My question is whether do you know of a better solution that doesn't use reflection.
Thanks.

Storing and processing RPG Weapons, Spells, Classes C#

So I've got a text-based RPG I've been brainstorming over with a few of my friends. We've got the whole principle down. Here's how it'll work:
Spells will be split between classes (Warrior, Mage, Rogue etc)
Each player can select let's say 3 spells to use in battle of the class specific let's say 10.
The problem that I've got at the moment is that I have no clue how to store spells. I could just do this:
public interface IClass {
string name {get; set;}
//some other features
}
public class Warrior : IClass {
public string name {get; set;} = "Warrior";
//again, some other features
}
public interface ISpell {
string name {get; set;}
IClass classReq {get; set;}
string description {get; set;}
double CalculateDamage(double d);
}
public class SlamAttack : ISpell {
public string name {get; set;} = "Slam Attack";
public IClass classReq {get; set;} = new Warrior();
public string description {get; set;} = "Do 10 damage, then Stun the target";
double CalculateDamage(double d) {} //Do what description says
}
public class MagicBoltThing : ISpell {
public string name {get; set;} = "Magic Bolt";
public IClass classReq {get; set;} = new Wizard(); //Just another class
public string description {get; set;} = "Do 12-15 damage";
double CalculateDamage(double d) {} //Do what description says
}
//and soooo on
This last part is what I would've loved to avoid (defining 40 different classes just so each CalculateDamage() does something different), but I gave up on that. So I decided to something with a database, but I never worked with databases before, so I just did somethin like this, and use it with reflection:
SpellID | SpellName | SpellClass
---------------------------------------
1 | Magic Bolt | MagicBoltThing
2 | Slam Attack | SlamAttack
Reflection part looks somethin like this:
var type = Type.GetType($"MyNameSpace.Spells.{spellNanme}"); //spellName is just the name of the spell I got from the user by typing into the console for example
dynamic spell = Activator.CreateInstance(type); //dynamic is the only way I managed to get this to work, because for some reason casting, broke the entire thing
So is there a better way of going about this... entire thing. It feels extremely clunky and it's kinda hard to work with + apparently a lot of ppl here say that to not use reflection. So is there a better way to store and proccess spells (either a better way of storage than a database, or better way to get classes from a string other than reflection)?

Interface and exposing class as property

I am looking at this code from a peer of mine and am a little confused as to how this makes sense:
public class CA
{
public CurrType CT {get; set;}
}
public interface ICharge
{
CA a {get; set;}
CurrType CT {get; set;}
}
public enum CurrType {X=0, Y=1}
public class Ch : ICharge
{
public CA a {get; set;}
public CurrType CT {get; set;}
}
I understand that interfaces contain properties but cant make any sense of the above code specifically:
1) Can the interface ICharge contain a class as a property?
2) Isnt some circular reference going on?
Isnt some circular reference going on?
No, there is no circular reference going on.
Can the interface ICharge contain a class as a property?
It sure can - why did you think it couldn't? This is perfectly normal usage - the interface is specifying that that property will contain an instance of that class (i.e. an object of that type). Why a class? Because classes are everywhere - even a lot of the basic .Net types are classes. A string is a class. You can't do everything with primitive value types :)
I can't answer why there is two different usages of CurrType in Ch (one at the root level, one in the CA instance), that's for you to figure out.

Sorting a list of different objects by shared property in C#

I have class Message
public DateTime DateCreated {get; set;}
public int MessageId {get; set;}
I also have class Activity:
public DateTime DateCreated {get; set;}
public int ActivityId {get; set;}
In my db, I use EF to query for both items:
db.Messages.ToList();
db.Activities.ToList();
I need to take these two lists, push them into a single list, and then sort by DateCreated. I can use inheritance to make Activity and Message inherit from some generic "Dated" class, but it feels messy, especially since these classes are already inheriting from other classes.
What's the proper way to achieve this?
You may use interface in this case:
public interface IDateCreated
{
DateTime DateCreated { get; set; }
}
implement this interface in your classes and after this you will create
var list = new List<IDateCreated>();
list.AddRange(db.Messages.ToList());
list.AddRange(db.Activities.ToList());
var result = list.OrderBy(x => x.DateCreated);
with an interface
public interface IDatedObject
{
DateTime DateCreated {get;}
}
Now make both classes implement the interface and store in a list of the interface.
When merging into one list, all elements should have the same type, while you don't have an intermediate type, just try an anonymous type:
var list = db.Messages.ToList().Select(x=>new{x.DateCreated, Id = x.MessageId})
.Concat(db.Activities.ToList().Select(x=>new{x.DateCreated,Id = ActvitiyId})
.OrderBy(x=>x.DateCreated).ToList();
You can use System.Collections.SortedList whose add method include a key and value parameter: MSDN

IEnumerable<T> question

Why it is not ok to use IEnumerable<T> as a type for a property within a class
for instance something like
public class Example
{
public IEnumerable<Int32> Ids {get; private set;}
publicIEnumerable<string> Names {get; private set;}
}
Sorry the problem was not that it wasn't compiling, I missed the public accessors on writing the stuff here, the question was why not to use IEnumerable for a property. But as I read further, I realized that if we only need something to iterate through and not modify (add, remove) than this (using IEnumerable ) is perfectly acceptable.
The problem is that the default accessibility of members in classes is already private, so your code is equivalent to:
public class Example
{
private IEnumerable<int> Ids {get; private set;}
private IEnumerable<string> Names {get; private set;}
}
That fails to compile because when you include an extra access modifier for a getter or setter, it has to be more restrictive than the overall access of the property. It isn't in this case.
If you make the overall property public though, it will compile with no problems:
public class Example
{
public IEnumerable<int> Ids {get; private set;}
public IEnumerable<string> Names {get; private set;}
}
(That's assuming you have a using directive for the System.Collections.Generic namespace, of course.)

Categories

Resources