here is a simple example to clear my intentions.
class A {
public int Id
public string Name
public string Hash
public C c
}
class B {
public int id
public string name
public C c
}
class C {
public string name
}
var a = new A() { Id = 123, Name = "something", Hash = "somehash" };
var b = new B();
I want to set b's properties from a. I have tried something but no luck.
public void GenericClassMatcher(object firstModel, object secondModel)
{
if (firstModel != null || secondModel != null)
{
var firstModelType = firstModel.GetType();
var secondModelType = secondModel.GetType();
// to view model
foreach (PropertyInfo prop in firstModelType.GetProperties())
{
var firstModelPropName = prop.Name.ElementAt(0).ToString().ToLower(System.Globalization.CultureInfo.InvariantCulture) + prop.Name.Substring(1); // lowercase first letter
if (prop.PropertyType.FullName.EndsWith("Model"))
{
GenericClassMatcher(prop, secondModelType.GetProperty(firstModelPropName));
}
else
{
var firstModelPropValue = prop.GetValue(firstModel, null);
var secondModelProp = secondModelType.GetProperty(firstModelPropName);
if (prop.PropertyType.Name == "Guid")
{
firstModelPropValue = firstModelPropValue.ToString();
}
secondModelProp.SetValue(secondModel, firstModelPropValue, null);
}
}
}
}
What shall I do?
It sounds like you are trying to map one class to another. AutoMapper is the best tool I've come across to do this.
public class A
{
public int Id;
public string Name;
public string Hash;
public C c;
}
public class B
{
public int id;
public string name;
public C c;
}
public class C
{
public string name;
}
class Program
{
static void Main(string[] args)
{
var a = new A() { Id = 123, Name = "something", Hash = "somehash" };
var b = new B();
AutoMapper.Mapper.CreateMap<A, B>();
b = AutoMapper.Mapper.Map<A, B>(a);
Console.WriteLine(b.id);
Console.WriteLine(b.name);
Console.ReadLine();
}
}
Related
I have 2 classes as you can see :
static void Main(string[] args)
{
object m = (??????)"salam";
}
public class A
{
public string name { set; get; }
public static implicit operator A(string _name)
{
A aa = new A();
aa.name = _name;
return aa;
}
}
public class B
{
public string family { set; get; }
public static implicit operator B(string _family)
{
B bb = new B();
bb.family = _family;
return bb;
}
}
I need to cast my string in runtime in this line :
object m = (??????)"salam";
Is there any solution to pass my class name as a string to cast my value .for example in runtime I need to cast "salam" to A or maybe B
The static cast is working good like this
object m = (A)salam";
object m = (B)"salam";
But I need to cast my string in runtime
Type x=null;
If(condition)
x can be type of A
else
x can be type of B
object m = (x)"salam";
You need to use Interfaces for such a need. The following code shows how to do so.
To simulate your situtation, I wrote a method to return either A or B based on time.
Here the list contains a bunch of objects which may be of Type A or B, depending on the second of execution. In the real-world scenario, you would get your types in various other ways.
public class StackOverflowQuestion
{
public static void Run()
{
List<IBase> list = new List<IBase>();
string types = "";
for (int i = 0; i < 10; i++)
{
var randomType = GiveMeARandomIBaseType();
System.Threading.Thread.Sleep(750);
IBase hello = randomType.Convert("salam");
list.Add(hello);
types += hello.GetType().Name + ",";
}
types = types.Trim(',');
//sample result : B,B,A,B,A,A,B,A,B,B
}
static IBase GiveMeARandomIBaseType() {
if (DateTime.Now.Second % 2 == 0)
return new A();
else
return new B();
}
}
public interface IBase {
public IBase Convert(string s);
}
public static class MyExtensions {
public static T Convert<T>(this string str, IBase b) where T : IBase {
try
{
return (T)b.Convert(str);
}
catch (Exception)
{
return default;
}
}
}
public class A : IBase
{
public IBase Convert(string s) {
return (A)s;
}
public string name { set; get; }
public static implicit operator A(string _name)
{
A aa = new A();
aa.name = _name;
return aa;
}
}
public class B : IBase
{
public IBase Convert(string s)
{
return (B)s;
}
public string family { set; get; }
public static implicit operator B(string _family)
{
B bb = new B();
bb.family = _family;
return bb;
}
}
I had a similar problem and after all the study and time, I was able to approach the desired result in the following way.
I used an internal method to access (the inside of) the class and this method returns the cast desired result.
Step 1: in class
public class A
{
public string Name { set; get; }
public static implicit operator A(string name)
{
return new A
{
Name = name
};
}
public A GetCasting(object a)
{
A i = (A)a;
return i;
}
}
public class B
{
public string Family { set; get; }
public static implicit operator B(string family)
{
return new B
{
Family = family
};
}
public B GetCasting(object b)
{
B i = (B)b;
return i;
}
}
Step 2: in controller or code
var className = "A";
var classMethod = "GetCasting";
var classType = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsClass && t.Name == className).FirstOrDefault();
var classInstance = Activator.CreateInstance(classType);
var castMethod = classType.GetMethod(classMethod);
var yourObject = "salam";
var objectData = new object[] { yourObject };
var resultObject = castMethod.Invoke(classInstance, objectData);
I have two classes
public class ClassA
{
public int ID { get; set; }
public string Countries {get;set;}
public string City { get;set; }
}
and
public class ClassB
{
public int ID { get; set; }
public string Countries {get;set;}
public string Village{ get;set; }
}
These two classes are in another class
public class ComponentClass
{
public List<ClassA> classAObj { get; set; }
public List<ClassB> classBObj { get; set; }
}
The data for the ComponentClass is coming from third party where the data for ClassA and ClassB is similar in structure. "City" in ClassA will have data in comma separated values "Manchester,Sydney" etc similarly with Village as well with comma separated values.
Now I am building a customized object at business layer where I am iterating through each property of ComponentClass and extracting information.
Main()
{
ComponentClass[] c = //Data from 3rd party;
foreach(var data in c)
{
Parent p = new Parent();
if(data.classAObj.count > 0)
{
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
List<string> sep = data.City.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
if(data.classBObj.count > 0)
{
Star s2 = new Star();
s2.Area = "infinite";
s2.Color = "red";
List<string> sep = data.Village.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s2.Values.Add(t);
}
p.Curves.Add(s);
}
}
}
In the code above , the two if statements are doing exactly the same operation apart from property names "City" and "Village". I want to simplify this by making use of any design pattern possibly strategy pattern which I just know theoretically or any other patterns.
Here is what I have tried :
public abstract class Base
{
public int ID { get; set; }
public string Countries {get;set;}
}
public class ClassA : Base
{
public string City { get;set; }
}
public class ClassB : Base
{
public string Village{ get;set; }
}
I want to make it as a common factory method which will do the looping and build the object for me for avoiding duplication of the code
public void CommonMethod(Base)
{
// How do I differentiate the properties for looping
}
If the goal is to reduce the code repetition, the two statements could be refactored into a single action as follows.
foreach(var data in c)
{
Parent p = new Parent();
Action<string> iAction = iString =>
{
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
List<string> sep = iString.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
if(data.classAObj.count > 0)
{
iAction(data.City);
}
if(data.classBObj.count > 0)
{
iAction(data.Village);
}
}
You have a same datatype properties for the both of the types in the json than you can create a single class to map it,
public class ClassA
{
public int ID { get; set; }
public string Countries {get;set;}
public string Areas{ get;set; }
}
public class ComponentClass
{
public List<ClassA> classAObj { get; set; }
public List<ClassA> classBObj { get; set; }
}
Main()
{
ComponentClass[] c = //Data from 3rd party;
foreach(var data in c)
{
Parent p = new Parent();
GetParent (p ,data.classAObj )
GetParent (p ,data.classBObj )
}
}
void GetParent (Parent p, ClassA classObj){
if(data.classAObj.count > 0)
{
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
List<string> sep = data.Areas.Split(',').Select(string.Parse).ToList();
foreach(var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
return p ;
}
I would suggest inheriting the ClassA and ClassB from a common base as you did and then casting them, after typechecking. If your only goal is minimizing code-repition this will get your there:
class Program
{
static void Main(string[] args)
{
ComponentClass[] c = new List<ComponentClass>().ToArray();//Data from 3rd party;
foreach (var data in c)
{
Parent p = new Parent();
if (data.classObjs.Count > 0)
{
Star s = new Star
{
Area = "infinite",
Color = "red"
};
foreach (var b in data.classObjs)
{
string bStr = b.GetType() == typeof(ClassA) ? ((ClassA)b).City : ((ClassB)b).Village;
bStr = bStr.Split(',').Select(string.Parse).ToList();
TinyStar t = new TinyStar
{
smallD = bStr
};
s.Values.Add(t);
}
p.Curves.Add(s);
}
}
}
public class ComponentClass
{
public List<ClassObj> classObjs { get; set; }
}
public class ClassObj
{
public int ID { get; set; }
public string Countries { get; set; }
}
public class ClassA : ClassObj
{
public string City { get; set; }
}
public class ClassB : ClassObj
{
public string Village { get; set; }
}
}
It might be necessary to refactor the tenary to if...else or switch depending on if you add more classes of type ClassObj.
Be warned though that GetType actually queries the assembly (at runtime) and should be used with caution from a performance point of view as it can slow down applications a lot when executed often.
I have used reflection, check if it works for you
public static void CommonMethod(dynamic collection)
{
Parent p = new Parent();
Star s = new Star();
s.Area = "infinite";
s.Color = "red";
foreach (var data in collection)
{
var properties = data.GetType().GetProperties();
foreach (var p in properties)
{
string propertytName = p.Name;
var propertyValue = p.GetValue(data, null);
if (propertytName == "City" || propertytName == "Village")
{
List<string> sep = propertyValue.Split(',').ToList();
foreach (var b in sep)
{
TinyStar t = new TinyStar();
t.smallD = b;
s.Values.Add(t);
}
p.Curves.Add(s);
}
}
}
}
static void Main(string[] args)
{
ComponentClass[] c Data from 3rd party;
foreach (var data in c)
{
CommonMethod(data.classAObj);
CommonMethod(data.classBObj);
}
}
I have a big class with a lot of properties (BigClass). I need to make a new class (SmallClass) with only some of those properties. This SmallClass must use all the overlapping properties from BigClass. What is the easiest way to do this without having to manually assign all the properties in the constructor of SmallClass like I do below:
class BigClass
{
public int A { get; }
public int B { get; }
public int C { get; }
public int D { get; }
public int E { get; }
public BigClass(int a, int b, int c, int d, int e)
{
A = a;
B = b;
C = c;
D = d;
E = e;
}
}
class SmallClass
{
public int A { get; }
public int B { get; }
public int C { get; }
public SmallClass(BigClass bigClass)
{
// I don't want to do all this manually:
A = bigClass.A;
B = bigClass.B;
C = bigClass.C;
}
}
Create a helper class:
public class Helper
{
public static void CopyItem<T>(BigClass source, T target)
{
// Need a way to rename the backing-field name to the property Name ("<A>k__BackingField" => "A")
Func<string, string> renameBackingField = key => new string(key.Skip(1).Take(key.IndexOf('>') - 1).ToArray());
// Get public source properties (change BindingFlags if you need to copy private memebers as well)
var sourceProperties = source.GetType().GetProperties().ToDictionary(item => item.Name);
// Get "missing" property setter's backing field
var targetFields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField).ToDictionary(item => renameBackingField(item.Name));
// Copy properties where target name matches the source property name
foreach(var sourceProperty in sourceProperties)
{
if (targetFields.ContainsKey(sourceProperty.Key) == false)
continue; // No match. skip
var sourceValue = sourceProperty.Value.GetValue(source);
targetFields[sourceProperty.Key].SetValue(target, sourceValue);
}
}
}
Then in your SmallClass constructor:
public SmallClass(BigClass bigClass)
{
Helper.CopyItem(bigClass, this);
}
This should work even if you only have property getters.
You can make CopyItem to work with all types by changing its declaration;
public static void CopyItem<U, T>(U source, T target)
Here's a simple class and a derived class:
class A { public int val; }
class B : A { }
I'd like a method Inc which works on both A and B instances that returns a new instance with val incremented by 1.
One way to approach this is to define Inc as an extension method:
static class Extensions
{
public static T Inc<T>(this T obj) where T : A, new()
{
return new T() { val = obj.val + 1 };
}
}
This seems to work. In the following example, a0.val is 11 and b0.val is 21.
var a = new A() { val = 10 };
var b = new B() { val = 20 };
var a0 = a.Inc();
var b0 = b.Inc();
My question is, is there a way to define Inc as a direct member of A and have it work as above?
If I define A like this:
class A
{
public int val;
public T Inc<T>() where T : A, new()
{
return new T() { val = val + 1 };
}
}
I then need to qualify the type when I call Inc:
var a = new A() { val = 10 };
var b = new B() { val = 20 };
var a0 = a.Inc<A>();
var b0 = b.Inc<B>();
Is there a way to go the member method route without having to qualify the type?
I don't think it's possible without implementing a new version of the method on each subclass, i.e,:
class A
{
public int val;
public virtual A Inc()
{
return new A { val = val + 1 };
}
}
class B : A
{
public new B Inc()
{
return new B { val = val + 1 };
}
}
So, you practically want to create clone of object with different value for some field:
class A {
public int val;
protected virtual A CloneInternal() {
return (A)MemberwiseClone();
}
public A Inc() {
A a=CloneInternal();
++a.val;
return a;
}
}
class B:A {
public new B Inc() {
return (B)base.Inc();
}
}
static void Main() {
A a=new B();
a=a.Inc();
Console.WriteLine(a.GetType());
}
Neither I don't think it's possible. You should provide a hint in order to make compiler guesses proper type for T.
You might try with static method:
public static T Inc<T>(T source) where T : A, new()
{
return new T() { val = source.val + 1 };
}
Then,
var b = new B { val = 20 };
var b0 = A.Inc(b);
But it's not an answer since you wanted a member method. I would rather go with extensions method.
abstract class Base
{
public int val { get; set; }
public virtual Base Inc() { return null; }
}
class A : Base
{
public override Base Inc()
{
return new A { val = val + 1 };
}
}
class B : A
{
public override Base Inc()
{
return new B { val = val + 2 };
}
}
Maybe using a abstract base class is better....
Base bClass = new B();
B bInc = bClass.Inc() as B;
One more way
interface IInc
{
int val { get; set; }
IInc GetNew();
}
class A : IInc
{
public int val
{
get;
set;
}
public virtual IInc GetNew()
{
return new A();
}
public IInc Inc()
{
var newObj = GetNew();
newObj.val++;
return newObj;
}
}
class B : A
{
public override IInc GetNew()
{
return new B();
}
}
and use like
var a = new A() { val = 10 };
var b = new B() { val = 20 };
var a0 = a.Inc();
var b0 = b.Inc();
Console.WriteLine(a0.val);
Console.WriteLine(b0.val);
I am trying to use reflection to identify where my object was created. For example:
public class MyClass
{
public int Id { get; set; }
public string Message { get; set; }
}
public static class Students
{
public static class FirstGrade
{
public static MyClass John = new MyClass { Id = 1, Message = "Some Text" };
}
}
Now somewhere else in my code I want to use the MyClass object John and with that object I want to determine where John was created so that I can identify that he is a student in First Grade. I would also like to know the object name "John" as this could change:
MyClass student = Students.FirstGrade.John;
I think below is what you are asking for. Alternatively if you want to know where an object was truly created and not just where it is referenced then you could access the a System.Diagnostics.StackTrace object inside the MyClass constructor.
As others have mentioned, it seems like the design should be reconsidered.
public static class Students
{
public static class FirstGrade {
public static MyClass John = new MyClass { Id = 1, Message = "Some Text" };
}
public static class SecondGrade {
public static MyClass John = new MyClass { Id = 2, Message = "Some Text" };
}
public static Type FindStudent(MyClass s, out String varName) {
varName = null;
foreach (var ty in typeof(Students).GetNestedTypes()) {
var arr = ty.GetFields(BindingFlags.Static | BindingFlags.Public);
foreach (var fi in arr) {
if (fi.FieldType == typeof(MyClass)) {
Object o = fi.GetValue(null);
if (o == s) {
varName = fi.Name;
return ty;
}
}
}
}
return null;
}
public static void FindJohn() {
String varName = null;
Type ty = FindStudent(SecondGrade.John, out varName);
MessageBox.Show(ty == null ? "Not found." : ty.FullName + " " + varName);
}
}