私の質問はこのコードに示されています
私はそのようなクラスがあります
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;
}
彼が言いたいのは:
「同じプロパティのほとんどを共有する2つのクラスがある場合、クラスa
からクラスb
にオブジェクトをキャストし、共有プロパティ名を介してシステムに自動的に割り当てを理解させることができますか?」
オプション1:反射を使用する
欠点:思ったよりも遅くなります。
オプション2:1つのクラスを別のクラスから派生させます。最初のクラスは共通のプロパティを持ち、その他はその拡張です。
欠点:連結!アプリケーションの2つのレイヤーに対してこれを行うと、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>();
}
メソッドキャストは、2つのオブジェクト間の共通プロパティをチェックし、自動的に割り当てを行います。
変換はすでに定義されています。キャストできるようにしたい場合は、さらに一歩進めます。例えば:
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;
}
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;
}
クラス構造を次のように変更できます。
public class maincs : sub1
{
public int d;
}
public class sub1
{
public int a;
public int b;
public int c;
}
その後、sub1のリストを保持し、そのうちのいくつかをmaincにキャストできます。
キャスト演算子に明示的なオーバーロードを提供できます。
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のパラメータタイプを指定します。
このコードを使用すると、同じ名前と同じタイプのプロパティの任意のクラスオブジェクトを別のクラスオブジェクトにコピーできます。
JavaScriptSerializer JsonConvert = new JavaScriptSerializer();
string serializeString = JsonConvert.Serialize(objectEntity);
objectViewModel objVM = JsonConvert.Deserialize<objectViewModel>(serializeString);
次のコードを使用すると、同じ名前と同じタイプのプロパティのクラスオブジェクトを別のクラスオブジェクトにコピーできます。
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
にコピーします。
ここにはいくつかの素晴らしい答えがあります。同じ名前のプロパティが存在する場合、それらが同じタイプであるとは想定できないため、ここに少し型チェックを追加したかっただけです。ここに私の提供物がありますが、これは以前の非常に優れた答えを拡張したもので、少し不具合がありました。
このバージョンでは、消費者が除外するフィールドを指定することを許可し、デフォルトでデータベース/モデル固有の関連プロパティを除外することもできます。
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;
}
var obj = _account.Retrieve(Email, hash);
AccountInfoResponse accountInfoResponse = new AccountInfoResponse();
if (obj != null)
{
accountInfoResponse =
JsonConvert.
DeserializeObject<AccountInfoResponse>
(JsonConvert.SerializeObject(obj));
}