简体   繁体   中英

Runtime assignment of data based on target class type

I have 5 different classes with same properties but with a different namespace.

For example:

MyNameSpace1.Class1  - FirstName, LastName, Age
MyNameSpace2.Class2 -  FirstName, LastName, Age

and so on

.

All the classes have the same properties - for say, FirstName, LastName, Age etc.

private void AssignData(int order, string firstName, string lastName)
{
  if(order==1)
 {
   var result=new MyNameSpace1.Class1();
   result.FirstName= firstName;
   result.LastName=lastName;
 }
 if(order==2)
 {
   var result=new MyNameSpace2.Class2();
   result.FirstName= firstName;
   result.LastName=lastName;
 }

}

Above, I have given just two properties, in my real example, there are multiple properties, that get assigned.

I tried to simplify that as

private void AssignData(int order, string firstName, string lastName)
{
 if(order==1)
 {
   var result= GetInstance<MyNameSpace1.Class1>();
   result.FirstName=firstName;
   result.LastName=lastName;
 }
 if(order==2)
 {
   var result= GetInstance<MyNameSpace2.Class2>();
   result.FirstName=firstName; //repeated code , don’t want to use dynamic, 
                              //as I will not know the compile time issues.
   result.LastName=lastName;
 }

}

Seems, I am repeating same code again, is there an option, where I will need to assign firstName, lastName directly just once and create runtime instance of the class?

private T GetInstance<T>()
{
  return Activator.CreateInstance<T>();
}

What i am trying to achieve is

private void AssignData(int order, string firstName, string lastName)
{
  var result; //this will not compile, object might, prefer not to use dynamic
  if(order==1)
  {
   result= GetInstance<MyNameSpace1.Class1>();
  }
  if(order==2)
  {
   result= GetInstance<MyNameSpace2.Class2>();
  }
  result.FirstName=firstName;//just do assignments 1 time
  result.LastName=lastName;
}

First and easiest option would be just using dynamic type:

class MyClass
{
    public int MyProperty { get; set; }
}

private dynamic GetInstance<T>()
{
    return Activator.CreateInstance<T>();
}

var instance = GetInstance<MyClass>();
instance.MyProperty = 5;
Console.WriteLine(instance.MyProperty);

so I would not recommend cause it is considered not very performant.

Second option would using reflection like this:

var instance = GetInstance<MyClass>();
typeof(MyClass).GetProperty("MyProperty")
    .GetSetMethod()
    .Invoke(instance, new object[] { 5}); // sets MyProperty to 5

You can "cache" result of GetSetMethod and reuse it, cause reflection is slow also.

Last option is reflection + expression trees(where you can generate "whole" method to set all variables):

var type = typeof(MyClass);
var method = type.GetProperty(nameof(MyClass.MyProperty)).GetSetMethod();
var cls = Expression.Parameter(typeof(MyClass));
var val = Expression.Parameter(typeof(int));
var call = Expression.Call(cls, method, val);
// this action should be cached
var act = Expression.Lambda<Action<MyClass, int>>(call, cls, val).Compile();

var instance = GetInstance<MyClass>();
act(instance, 5); // sets MyProperty to 5

An again do not forget to cache result of Expression.Lambda.Compile for type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM