如何在 C# 中克隆类型 T?
How to clone a type T in c#?
我有一个类型 Foo
如下:
[Alias("Boo")]
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
我正在保存对象属性更改的历史记录,出于性能原因,我想创建第二个 table 来推送所有历史记录。不幸的是,OrmLite 不支持(afaik)每种类型的多个 tables。定义时将简单地使用别名而不是类型名称。
由于我使用的是通用数据控制器,因此我需要克隆实际类型 T
(使用不同的名称Boo
)。我不需要 convert/cast 两种类型之间的对象,但如果可能的话也会有所帮助。
您可以添加并实施 IClonable<T>
吗?
interface ICloneable<T>
{
T Clone();
}
[Alias("Boo")]
public class Foo : ICloneable<Foo>
{
public int Id { get; set; }
public string Name { get; set; }
public Foo Clone() { ... }
}
您可以使用继承来克隆定义
"Cloning" 实例非常模糊:它是深度克隆还是浅层克隆?如果很深,有多深?它会包括对其他可能的 POCO 的引用吗?如果是这样,它将如何包括它们?用身份证?使用副本?
此外,将对象的完整副本存储在不同的 table 中并不是实现历史记录的方法。
如果我是你,我会使用不同的类型来及时存储序列化的更改,然后在你的实体中有一个更改列表。
这就是我在最近的一些项目的 POCO 中实现它的方式(使用 entity framework 进行持久化,根据需要为 OrmLite 进行调整...还删除了一些内容):
/* BaseEntity just adds "Id" and some other properties common to all my
POCOs */
public class EntityHistory : BaseEntity
{
/* ... Other properties removed for clarity ... */
public Guid TransactionId { get; set; }
public DateTime TransactionTime { get; set; }
public string OldValues { get; set; }
public string NewValues { get; set; }
}
然后有一个基本实体(或一个接口,我使用基本实体是因为我不需要额外的多重继承并且避免我在所有 类 中编写相同的 属性)对于那些需要将历史存储在以下位置的实体:
public abstract class BaseTrackedEntity : BaseEntity, IAuditableEntity, IChangeTrackedEntity
{
/* ... Other properties removed for clarity ... */
public ICollection<EntityHistory> Histories { get; set; }
}
然后您的实体将继承自 BaseTrackedEntity
。
在对数据库进行持久化更改后,您会发现更改(在 EF 中很容易,它给您一个 ChangeSet
,不知道 OrmLite,但如果它不提供意味着,您可以使用反射来解决它),从加载的实体到保存的实体,并将它们序列化为 EntityHistory
实例(在 OldValues
和 NewValues
中)并添加到 Histories
列表。我使用 JSON 但你可以使用任何东西。
这既适用于日志记录目的(我还没有复制我的日志记录属性 - 例如 User
、CreationTime
和东西 - 但它们会在 BaseTrackedEntity
) 和 Undoing
(如果需要,EntityHistory
中的 TransactionId
组撤消阶段),它的性能非常好(比每次更新克隆和存储整个对象一次要好得多)而且很容易实施和维护。
解决方案变得比我想象的更容易 - 尽管一开始我没有想到:继承!
由于我无法控制 Foo
类,我无法手动编写一个新类型来反映它(成员可能会在 Foo
中更改)。创建一个继承自 Foo
且未定义额外成员的新类型 Boo
将允许使用 OrmLite 使用新名称进行转换和 table 创建。
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Boo : Foo
{
}
我有一个类型 Foo
如下:
[Alias("Boo")]
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
我正在保存对象属性更改的历史记录,出于性能原因,我想创建第二个 table 来推送所有历史记录。不幸的是,OrmLite 不支持(afaik)每种类型的多个 tables。定义时将简单地使用别名而不是类型名称。
由于我使用的是通用数据控制器,因此我需要克隆实际类型 T
(使用不同的名称Boo
)。我不需要 convert/cast 两种类型之间的对象,但如果可能的话也会有所帮助。
您可以添加并实施 IClonable<T>
吗?
interface ICloneable<T>
{
T Clone();
}
[Alias("Boo")]
public class Foo : ICloneable<Foo>
{
public int Id { get; set; }
public string Name { get; set; }
public Foo Clone() { ... }
}
您可以使用继承来克隆定义
"Cloning" 实例非常模糊:它是深度克隆还是浅层克隆?如果很深,有多深?它会包括对其他可能的 POCO 的引用吗?如果是这样,它将如何包括它们?用身份证?使用副本?
此外,将对象的完整副本存储在不同的 table 中并不是实现历史记录的方法。
如果我是你,我会使用不同的类型来及时存储序列化的更改,然后在你的实体中有一个更改列表。
这就是我在最近的一些项目的 POCO 中实现它的方式(使用 entity framework 进行持久化,根据需要为 OrmLite 进行调整...还删除了一些内容):
/* BaseEntity just adds "Id" and some other properties common to all my
POCOs */
public class EntityHistory : BaseEntity
{
/* ... Other properties removed for clarity ... */
public Guid TransactionId { get; set; }
public DateTime TransactionTime { get; set; }
public string OldValues { get; set; }
public string NewValues { get; set; }
}
然后有一个基本实体(或一个接口,我使用基本实体是因为我不需要额外的多重继承并且避免我在所有 类 中编写相同的 属性)对于那些需要将历史存储在以下位置的实体:
public abstract class BaseTrackedEntity : BaseEntity, IAuditableEntity, IChangeTrackedEntity
{
/* ... Other properties removed for clarity ... */
public ICollection<EntityHistory> Histories { get; set; }
}
然后您的实体将继承自 BaseTrackedEntity
。
在对数据库进行持久化更改后,您会发现更改(在 EF 中很容易,它给您一个 ChangeSet
,不知道 OrmLite,但如果它不提供意味着,您可以使用反射来解决它),从加载的实体到保存的实体,并将它们序列化为 EntityHistory
实例(在 OldValues
和 NewValues
中)并添加到 Histories
列表。我使用 JSON 但你可以使用任何东西。
这既适用于日志记录目的(我还没有复制我的日志记录属性 - 例如 User
、CreationTime
和东西 - 但它们会在 BaseTrackedEntity
) 和 Undoing
(如果需要,EntityHistory
中的 TransactionId
组撤消阶段),它的性能非常好(比每次更新克隆和存储整个对象一次要好得多)而且很容易实施和维护。
解决方案变得比我想象的更容易 - 尽管一开始我没有想到:继承!
由于我无法控制 Foo
类,我无法手动编写一个新类型来反映它(成员可能会在 Foo
中更改)。创建一个继承自 Foo
且未定义额外成员的新类型 Boo
将允许使用 OrmLite 使用新名称进行转换和 table 创建。
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Boo : Foo
{
}