如何基于另一个对象创建新对象?
How can I create new object based on another one?
我有一些没有用的对象,比方说,有 30 个属性。其中一半对我有用,所以我想创建仅具有我需要的属性的新有用对象,这样其余的就不会在对象可视化器中占用 space。我不想定义新的 class 并键入它们。我想要
var list = new List<SomeType> { usefulProp1, usefulProp2, ... };
var usefulObject = new NewItem(notUsefulObject, list);
其中 SomeType 不是字符串(列表不包含 属性 个名称)。
如果它是永久性的,那么正确的做法是创建一个 class 从您的基础 class 继承并仅填充您需要的属性。
public UsefulObject : NotUsefulObject
{
public int MyProperty
{
get
{
return base.MyProperty; // this is arbitrary you can do it however you want.
}
set
{
MyProperty = value;
}
}
}
然后您可以随心所欲地使用您的重用对象。
var list = new List<UsefulObject>();
var list = new List<Expression<Func<object>>> { () => notUsefulObject.usefulProp1, () => notUsefulObject.usefulProp2... };
var nm = new AssemblyName("MyDynamicAssembly");
TypeBuilder tb = Thread.GetDomain().DefineDynamicAssembly(nm, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(nm.Name, nm.Name + ".dll").DefineType("NewItem", TypeAttributes.Public);
const MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
foreach (Expression b in list.Select(x => x.Body))
{
MemberInfo mi = ((MemberExpression)b).Member;
Type t = b.Type;
FieldBuilder fb = tb.DefineField(mi.Name.ToLower(), t, FieldAttributes.Private);
PropertyBuilder pb = tb.DefineProperty(mi.Name, PropertyAttributes.HasDefault, t, null);
MethodBuilder getBld = tb.DefineMethod("get_" + mi.Name, GetSetAttr, t, Type.EmptyTypes);
ILGenerator getGen = getBld.GetILGenerator();
getGen.Emit(OpCodes.Ldarg_0);
getGen.Emit(OpCodes.Ldfld, fb);
getGen.Emit(OpCodes.Ret);
MethodBuilder setBld = tb.DefineMethod("set_" + mi.Name, GetSetAttr, null, new[] { t });
ILGenerator setGen = setBld.GetILGenerator();
setGen.Emit(OpCodes.Ldarg_0);
setGen.Emit(OpCodes.Ldarg_1);
setGen.Emit(OpCodes.Stfld, fb);
setGen.Emit(OpCodes.Ret);
pb.SetGetMethod(getBld);
pb.SetSetMethod(setBld);
}
object usefulObject = Activator.CreateInstance(tb.CreateType());
因为你说这个问题是特定于对象可视化器的,所以最好的解决方案是为 class 创建一个 Debugger Type Proxy 可以用作代理。
[DebuggerTypeProxy(typeof(SomeTypeDebugView))]
public class SomeType
{
public string Foo { get; set; }
public string Bar { get; set; }
internal class SomeTypeDebugView
{
private SomeType _someType;
public SomeTypeDebugView(SomeType someType)
{
_someType = someType;
}
public string Foo { get { return _someType.Foo; } }
}
}
class Program
{
static void Main()
{
var someType = new SomeType();
someType.Foo = "foo";
someType.Bar = "bar";
Debugger.Break();
}
}
这将导致 Bar
默认隐藏在调试可视化工具中,除非您选择查看 "Raw Type"
如果您正在寻找更多的一次性调试类型,您可以使用匿名类型在手表中创建您需要的新类型 window,例如他的是 new {Foo = someType.Foo, Bar = someType.Bar }
这也可以与 LINQ 一起使用以在 IEnumerable 上执行 select,例如这里是 someTypeList.Select(x=> new {Foo = x.Foo, Bar = x.Bar})
我有一些没有用的对象,比方说,有 30 个属性。其中一半对我有用,所以我想创建仅具有我需要的属性的新有用对象,这样其余的就不会在对象可视化器中占用 space。我不想定义新的 class 并键入它们。我想要
var list = new List<SomeType> { usefulProp1, usefulProp2, ... };
var usefulObject = new NewItem(notUsefulObject, list);
其中 SomeType 不是字符串(列表不包含 属性 个名称)。
如果它是永久性的,那么正确的做法是创建一个 class 从您的基础 class 继承并仅填充您需要的属性。
public UsefulObject : NotUsefulObject
{
public int MyProperty
{
get
{
return base.MyProperty; // this is arbitrary you can do it however you want.
}
set
{
MyProperty = value;
}
}
}
然后您可以随心所欲地使用您的重用对象。
var list = new List<UsefulObject>();
var list = new List<Expression<Func<object>>> { () => notUsefulObject.usefulProp1, () => notUsefulObject.usefulProp2... };
var nm = new AssemblyName("MyDynamicAssembly");
TypeBuilder tb = Thread.GetDomain().DefineDynamicAssembly(nm, AssemblyBuilderAccess.RunAndSave).DefineDynamicModule(nm.Name, nm.Name + ".dll").DefineType("NewItem", TypeAttributes.Public);
const MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
foreach (Expression b in list.Select(x => x.Body))
{
MemberInfo mi = ((MemberExpression)b).Member;
Type t = b.Type;
FieldBuilder fb = tb.DefineField(mi.Name.ToLower(), t, FieldAttributes.Private);
PropertyBuilder pb = tb.DefineProperty(mi.Name, PropertyAttributes.HasDefault, t, null);
MethodBuilder getBld = tb.DefineMethod("get_" + mi.Name, GetSetAttr, t, Type.EmptyTypes);
ILGenerator getGen = getBld.GetILGenerator();
getGen.Emit(OpCodes.Ldarg_0);
getGen.Emit(OpCodes.Ldfld, fb);
getGen.Emit(OpCodes.Ret);
MethodBuilder setBld = tb.DefineMethod("set_" + mi.Name, GetSetAttr, null, new[] { t });
ILGenerator setGen = setBld.GetILGenerator();
setGen.Emit(OpCodes.Ldarg_0);
setGen.Emit(OpCodes.Ldarg_1);
setGen.Emit(OpCodes.Stfld, fb);
setGen.Emit(OpCodes.Ret);
pb.SetGetMethod(getBld);
pb.SetSetMethod(setBld);
}
object usefulObject = Activator.CreateInstance(tb.CreateType());
因为你说这个问题是特定于对象可视化器的,所以最好的解决方案是为 class 创建一个 Debugger Type Proxy 可以用作代理。
[DebuggerTypeProxy(typeof(SomeTypeDebugView))]
public class SomeType
{
public string Foo { get; set; }
public string Bar { get; set; }
internal class SomeTypeDebugView
{
private SomeType _someType;
public SomeTypeDebugView(SomeType someType)
{
_someType = someType;
}
public string Foo { get { return _someType.Foo; } }
}
}
class Program
{
static void Main()
{
var someType = new SomeType();
someType.Foo = "foo";
someType.Bar = "bar";
Debugger.Break();
}
}
这将导致 Bar
默认隐藏在调试可视化工具中,除非您选择查看 "Raw Type"
如果您正在寻找更多的一次性调试类型,您可以使用匿名类型在手表中创建您需要的新类型 window,例如他的是 new {Foo = someType.Foo, Bar = someType.Bar }
这也可以与 LINQ 一起使用以在 IEnumerable 上执行 select,例如这里是 someTypeList.Select(x=> new {Foo = x.Foo, Bar = x.Bar})