私が読んだ他の投稿から、これは不可能かもしれないようですが、私がやろうとしていることを投稿して、誰かが解決策を知っているかどうかを確認したいと思いました。
Telerik Open Accessドメインモデルから生成されたクラスに「Clone()」メソッドを追加しようとしています。問題ない。生成されたエンティティモデルに基本クラスを追加して、それらのクラスを基本クラスで識別できるようにする方法を理解することができました。(すべてのエンティティは基本クラスから継承します)
これらすべてのエンティティモデルクラスが自分自身を複製できるようにしたいと思います。私もその解決策を見つけました。(ディープクローニングオブジェクト)
これで基本クラスができました。その基本クラスから派生するすべてのクラスにClone()関数を追加したいと思います。だから...基本クラスはそれを置くのに自然な場所のようです...そうですか?
public abstract class DBEntityBase
{
/// <summary>
/// Gets a COPY of the instance in it's current state
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T Clone<T>()
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
}
}
基本クラスレベルでは、クローンを作成しているタイプがわからないため、保護された汎用Clone()メソッドを追加します。Clone()メソッドは、複製される特定のタイプを提供するために、エンティティモデル自体によって実装される必要があります。
public partial class DeliverableEntity
{
public new DeliverableEntity Clone()
{
return this.Clone<DeliverableEntity>();
}
}
これは正常に機能しますが、派生クラスがClone()メソッドを公開することを保証するものではないため、派生クラスがパブリックClone()メソッドを実装する必要があるベースに抽象Clone()メソッドを追加しました。
public abstract class DarkRoomDBEntityBase
{
/// <summary>
/// Gets a COPY of the instance in it's current state
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T Clone<T>()
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
}
/// <summary>
/// Gets a deep COPY of the entity instance
/// </summary>
/// <returns></returns>
public abstract DBEntityBase Clone();
}
基本クラス自体の戻り値の型を指定します。すべての実装は、DBEntityBaseに準拠する値を返さなければなりません。もちろん、すべての派生クラスはそれを返します。Clone()メソッドは派生クラス自体の型を返すので...これが機能することは理にかなっているようです。
DeliverableEntity originalEntity = new DeliverableEntity();
DeliverableEntity clonedEntity = originalEntity.Clone();
ただし、ビルド時にエラーが発生します。
「DeliverableEntity」は、継承された抽象メンバー「DBEntityBase.Clone()」を実装していません
おそらく戻り値の型が原因です。
Clone()メソッドを個別のユーティリティクラスに配置し、各エンティティモデルに直接実装することはできないことを知っています...これで問題を回避できます(おそらく多くの実装コードを節約できます)が、私はなぜこれが機能しないのか疑問に思ったままです。これを行う方法があるはずのようです。
更新
@Luannの最初の返信(ありがとう)に応えて、「オーバーライド」に変更しました...
public partial class DeliverableEntity
{
public override DeliverableEntity Clone()
{
return this.Clone<DeliverableEntity>();
}
}
そして今、次のエラーを受け取っています...
オーバーライドされたメンバー「DBEntityBase.Clone()」と一致するには、戻り値の型は「DBEntityBase」である必要があります
解決
Flynn1179のおかげで、私は再び前進することができました。将来の参考のために、ここで行ったことを文書化するのに少し時間がかかると思いました。
ORMのエンティティモデルごとに部分クラスを作成し、抽象メソッドを実装する代わりに、提案されているように単一の拡張メソッドを作成しました。
namespace DAL
{
public partial class DeliverableEntity : DBEntityBase
{
// ... Code generated from ORM
}
public partial class DeliverableItemEntity : DBEntityBase
{
// ... Code generated from ORM
}
public partial class DeliverableItemAttrEntity : DBEntityBase
{
// ... Code generated from ORM
}
}
namespace DAL
{
public static class EntityExtensionMethods
{
public static T Clone<T>(this T entity) where T: DBEntityBase
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(entity));
}
}
}
注意すべきいくつかの事柄...
今、クールな部分は、すべてのエンティティが関数にアクセスできることです...
// Create the original instances of the entities
DeliverableEntity origDeliverable = new DeliverableEntity();
DeliverableItemEntity origItem = new DeliverableItemEntity();
DeliverableItemAttrEntity origItemAttr = new DeliverableItemAttrEntity();
// now here's the magic
DeliverableEntity cloneDeliverable = origDeliverable.Clone();
DeliverableItemEntity cloneItem = origItem.Clone();
DeliverableItemAttrEntity cloneItemAttr = origItemAttr.Clone();
このソリューションは、実装が単一の場所で定義される基本クラスの単純さ(各派生クラスで個別に抽象メソッドを実装することを検討していたのに対し)に加えて、DBEntityBaseクラスに関連付けられているため、このソリューションが大好きです。名前空間は、基本クラスによって定義された「コントラクト」の一部になります。つまり、DBEntityBaseから派生したクラスがある場合はいつでも、それが利用可能であると期待できます。
人気のリクエストで..
拡張メソッドを試してください:
public T Clone<T>(this T obj) where T : DBEntityBase
{
return /* insert code that creates clone here */
}
正直に言うと、C#はそれが何の拡張であるかを正確に判断できないと思っていたので、これが機能するとは思いませんでした。どうやら、しかし、それはします!
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加