2010-09-08 7 views
20

мой вопрос показан в этом коделитая класса в другой класс или преобразовать класс в другой

У меня есть класс, как этот

public class maincs 
{ 
    public int a; 
    public int b; 
    public int c; 
    public int d; 
} 

public class sub1 
{ 
    public int a; 
    public int b; 
    public int c; 
} 


public void methoda (sub1 model) 
{ 
    maincs mdata = new maincs(){a = model.a , b = model.b , c= model.c} ; 

    // is there is a way to directly cast class sub1 into main like that  
    mdata = (maincs) model;  
} 
+1

Этот код не имеет смысла. Почтовый код, который компилируется (это не проблема, это проблема). –

+7

Довольно суровый. Отсутствие ключевого слова 'class' не имеет смысла. – nawfal

+0

Имеются существующие библиотеки картографа, написанные уже для этой цели. Они обрабатывают намного больше случаев. Вы можете это сделать. – nawfal

ответ

23

То, что он хочет сказать:

«Если у вас есть два класса, которые разделяют те же самые свойства, которые вы можете бросить объект из класса a к классу b и автоматически сделать систему понять назначение через общие имена свойств? "

Вариант 1: Использование отражения

Неудобство: Это собирается замедлять больше, чем вы думаете.

Вариант 2: Сделать один класс производным от другого, первого с общими свойствами и другим расширением этого.

Недостаток: в сочетании! если вы сделаете это для двух слоев в своем приложении, тогда два слоя будут соединены!

Пусть имеется:

class customer 
{ 
    public string firstname { get; set; } 
    public string lastname { get; set; } 
    public int age { get; set; } 
} 
class employee 
{ 
    public string firstname { get; set; } 
    public int age { get; set; } 
} 

Теперь здесь является расширением для типа объекта:

public static T Cast<T>(this Object myobj) 
{ 
    Type objectType = myobj.GetType(); 
    Type target = typeof(T); 
    var x = Activator.CreateInstance(target, false); 
    var z = from source in objectType.GetMembers().ToList() 
     where source.MemberType == MemberTypes.Property select source ; 
    var d = from source in target.GetMembers().ToList() 
     where source.MemberType == MemberTypes.Property select source; 
    List<MemberInfo> members = d.Where(memberInfo => d.Select(c => c.Name) 
     .ToList().Contains(memberInfo.Name)).ToList(); 
    PropertyInfo propertyInfo; 
    object value; 
    foreach (var memberInfo in members) 
    { 
     propertyInfo = typeof(T).GetProperty(memberInfo.Name); 
     value = myobj.GetType().GetProperty(memberInfo.Name).GetValue(myobj,null); 

     propertyInfo.SetValue(x,value,null); 
    } 
    return (T)x; 
} 

Теперь вы использовать его как это:

static void Main(string[] args) 
{ 
    var cus = new customer(); 
    cus.firstname = "John"; 
    cus.age = 3; 
    employee emp = cus.Cast<employee>(); 
} 

Метод литых проверяет общие свойства между двумя объектами и выполняет назначение автоматически.

+1

То, что я имею в виду точно –

+0

Хорошее решение, но, как вы сказали, накладные расходы и сложность :) – Noctis

+0

Думаю, вы пропустили использовать переменную 'z'. Он должен использоваться при инициализации var-членов, т.е. List members = z.Where (memberInfo => d.Select (c => c.Name) .ToList(). Содержит (memberInfo.Name)). ToList() ; – Aamol

5

Вы можете изменить структуру классов, чтобы:

public class maincs : sub1 
{ 
    public int d; 
} 

public class sub1 
{ 
    public int a; 
    public int b; 
    public int c; 
} 

Тогда вы можете сохранить список sub1 и бросить некоторые из них в mainc.

+0

Это тоже не скомпилировано. Возможно, вы забыли ключевое слово 'class' –

+0

К сожалению, это то, что я получаю для копирования/вставки. –

43

Вы уже определили преобразование, вам просто нужно сделать это на один шаг дальше, если вы хотите, чтобы его можно было отличить. Например:

public class sub1 
{ 
    public int a; 
    public int b; 
    public int c; 

    public static explicit operator maincs(sub1 obj) 
    { 
     maincs output = new maincs() { a = obj.a, b = obj.b, c = obj.c }; 
     return output; 
    } 
} 

Который затем позволяет сделать что-то вроде

static void Main() 
{ 
    sub1 mySub = new sub1(); 
    maincs myMain = (maincs)mySub; 
} 
+2

Даже лучше, чем выбранный ответ – Noctis

+1

Отличный ответ. Благодарю. – Ellis

+0

Есть ли какие-либо последствия для преобразования/кастинга из одного класса в другой с точными реквизитами, использующими ваш код? – Code

2

Вы можете обеспечить явную перегрузку оператора литом:

public static explicit operator maincs(sub1 val) 
{ 
    var ret = new maincs() { a = val.a, b = val.b, c = val.c }; 
    return ret; 
} 

Другим вариантом было бы использовать интерфейс, который имеет свойства a, b и c и реализует интерфейс для обоих классов. Тогда просто введите тип параметра methoda как интерфейс вместо класса.

1

Используя следующий код, вы можете скопировать любой объект класса в другой объект класса с тем же именем и свойствами того же типа.

public class CopyClass 
{ 
    /// <summary> 
    /// Copy an object to destination object, only matching fields will be copied 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    /// <param name="sourceObject">An object with matching fields of the destination object</param> 
    /// <param name="destObject">Destination object, must already be created</param> 
    public static void CopyObject<T>(object sourceObject, ref T destObject) 
    { 
     // If either the source, or destination is null, return 
     if (sourceObject == null || destObject == null) 
      return; 

     // Get the type of each object 
     Type sourceType = sourceObject.GetType(); 
     Type targetType = destObject.GetType(); 

     // Loop through the source properties 
     foreach (PropertyInfo p in sourceType.GetProperties()) 
     { 
      // Get the matching property in the destination object 
      PropertyInfo targetObj = targetType.GetProperty(p.Name); 
      // If there is none, skip 
      if (targetObj == null) 
       continue; 

      // Set the value in the destination 
      targetObj.SetValue(destObject, p.GetValue(sourceObject, null), null); 
     } 
    } 
} 

Метод вызова Как,

ClassA objA = new ClassA(); 
ClassB objB = new ClassB(); 

CopyClass.CopyObject(objOfferMast, ref objB); 

Он будет копировать objA в objB.

+1

Помните, что если вы используете это решение, вы можете столкнуться с проблемами, когда классы имеют одинаковое имя для свойств, но с разными типами. Например: 'public class A {public int Age {get; set;}}' и 'public class B {public string Age {get; set;}}' Вызвать исключение, если вы пытаетесь преобразовать от 'A' до' B' – Noctis

+0

Этот тип преобразования также может привести к огромным проблемам с производительностью. Используйте его тщательно и, конечно, не для for-loops. – RPDeshaies

11

Другой вариант заключается в использовании JSON сериализации и десериализации:

using Newtonsoft.Json; 

Class1 obj1 = new Class1(); 
Class2 obj2 = JsonConvert.DeserializeObject<Class2>(JsonConvert.SerializeObject(obj1)); 

Или:

public class Class1 
{ 
    public static explicit operator Class2(Class1 obj) 
    { 
     return JsonConvert.DeserializeObject<Class2>(JsonConvert.SerializeObject(obj)); 
    } 
} 

Который затем позволяет сделать что-то вроде

static void Main() 
{ 
    Class1 obj1 = new Class1(); 
    Class2 obj2 = (Class2)obj1; 
} 
+1

Да, с помощью сериализатора Newtonsoft json довольно просто и эффективно. Существует .Net-сериализатор, но я обнаружил, что Newtonsoft преуспевает .Net json serializer. Я нашел эту ссылку, которая дает краткое сравнение http://www.newtonsoft.com/json/help/html/JsonNetVsDotNetSerializers.htm – Aamol

1

Есть некоторые отличные ответы здесь, я просто хотел чтобы добавить немного проверки типа здесь, поскольку мы не можем предположить, что если свойства существуют с тем же именем, они имеют один и тот же тип. Вот мое предложение, которое распространяется на предыдущий, очень отличный ответ, поскольку у меня было несколько небольших сбоев.

В этой версии я разрешил потребителю указывать поля, которые должны быть исключены, а также по умолчанию исключать любые связанные с базой/моделью соответствующие свойства.

public static T Transform<T>(this object myobj, string excludeFields = null) 
    { 
     // Compose a list of unwanted members 
     if (string.IsNullOrWhiteSpace(excludeFields)) 
      excludeFields = string.Empty; 
     excludeFields = !string.IsNullOrEmpty(excludeFields) ? excludeFields + "," : excludeFields; 
     excludeFields += $"{nameof(DBTable.ID)},{nameof(DBTable.InstanceID)},{nameof(AuditableBase.CreatedBy)},{nameof(AuditableBase.CreatedByID)},{nameof(AuditableBase.CreatedOn)}"; 

     var objectType = myobj.GetType(); 
     var targetType = typeof(T); 
     var targetInstance = Activator.CreateInstance(targetType, false); 

     // Find common members by name 
     var sourceMembers = from source in objectType.GetMembers().ToList() 
            where source.MemberType == MemberTypes.Property 
            select source; 
     var targetMembers = from source in targetType.GetMembers().ToList() 
            where source.MemberType == MemberTypes.Property 
            select source; 
     var commonMembers = targetMembers.Where(memberInfo => sourceMembers.Select(c => c.Name) 
      .ToList().Contains(memberInfo.Name)).ToList(); 

     // Remove unwanted members 
     commonMembers.RemoveWhere(x => x.Name.InList(excludeFields)); 

     foreach (var memberInfo in commonMembers) 
     { 
      if (!((PropertyInfo)memberInfo).CanWrite) continue; 

      var targetProperty = typeof(T).GetProperty(memberInfo.Name); 
      if (targetProperty == null) continue; 

      var sourceProperty = myobj.GetType().GetProperty(memberInfo.Name); 
      if (sourceProperty == null) continue; 

      // Check source and target types are the same 
      if (sourceProperty.PropertyType.Name != targetProperty.PropertyType.Name) continue; 

      var value = myobj.GetType().GetProperty(memberInfo.Name)?.GetValue(myobj, null); 
      if (value == null) continue; 

      // Set the value 
      targetProperty.SetValue(targetInstance, value, null); 
     } 
     return (T)targetInstance; 
    } 
Смежные вопросы