web-dev-qa-db-ja.com

異なるアセンブリの2つの部分クラスが同じクラスを表すことは可能ですか?

「MyProject.Data」というプロジェクトに「Article」というクラスがあり、これがWebアプリケーションのデータレイヤーとして機能します。

「MyProject.Admin」という別のプロジェクトがあります。これは、データを表示/編集するためのWebベースの管理システムであり、ASP.NET Dynamic Dataを使用してビルドされました。

基本的に、一部のクラスを使用してArticleクラスを拡張し、そのプロパティの1つを「UIHint」エクステンダーで拡張して、通常の複数行テキストボックスをFCKEditコントロールに置き換えることができるようにします。

私の部分クラスとエクステンダーは次のようになります。

[MetadataType(typeof(ProjectMetaData))]
public partial class Project
{
}

public class ProjectMetaData
{
    [UIHint("FCKeditor")]
    public object ItemDetails { get; set; }
}

部分クラスが元の部分クラスと同じプロジェクト(MyProject.Dataプロジェクト)にある場合、これはすべて正常に機能します。

ただし、UIの動作はデータ層ではなく、管理層に配置する必要があります。したがって、このクラスをMyProject.Adminに移動します。

ただし、これを行うと、機能が失われます。

私の基本的な質問は、2つの部分的なクラスを別々のプロジェクトに持つことはできますが、両方が同じ「クラス」を参照することはできますか?

そうでない場合、データレイヤーロジックとUIロジックを混在させずに、私がやろうとしていることを達成する方法はありますか?

122
Jonathan

いいえ、2つの異なるアセンブリ(プロジェクト)で同じクラスを参照する2つの部分クラスを持つことはできません。アセンブリがコンパイルされると、メタデータが焼き付けられ、クラスは部分的ではなくなります。部分クラスを使用すると、同じクラスの定義を2つのファイルに分割できます。

169
Darin Dimitrov

前述のように、部分クラスはコンパイル時の現象であり、ランタイムではありません。アセンブリ内のクラスは、定義により完全です。

MVCの用語では、ビューコードをモデルコードから分離し、モデルのプロパティに基づいて特定の種類のUIを有効にする必要があります。 Martin Fowlerの優れた概要 MVC、MVP、その他のさまざまなフレーバーをご覧ください。デザインアイデアが豊富にあります。 Dependency Injection を使用して、UIに個々のエンティティと属性に対して実行可能なコントロールの種類を伝えることもできると思います。

懸念を分離するというあなたの目的は素晴らしいです。しかし、部分クラスはまったく異なる問題に対処することを目的としていました(主にコード生成と設計時モデリング言語で)。

13
Pontus Gagge

拡張メソッドとViewModelは、次のようにフロントエンドのデータ層オブジェクトを拡張する標準的な方法です。

データ層(クラスライブラリ、Person.cs):

namespace MyProject.Data.BusinessObjects
{
  public class Person
  {
    public string Name {get; set;}
    public string Surname {get; set;}
    public string Details {get; set;}
  }
}

表示レイヤー(Webアプリケーション)PersonExtensions.cs:

using Data.BusinessObjects
namespace MyProject.Admin.Extensions
{
  public static class PersonExtensions
  {
    public static HtmlString GetFormattedName(this Person person)
    {
       return new HtmlString(person.Name + " <b>" + person.Surname</b>);
    }
  }
}

ViewModel(拡張ビュー固有のデータ用):

using Data.BusinessObjects
namespace MyProject.Admin.ViewModels
{
  public static class PersonViewModel
  {
    public Person Data {get; set;}
    public Dictionary<string,string> MetaData {get; set;}

    [UIHint("FCKeditor")]
    public object PersonDetails { get { return Data.Details; } set {Data.Details = value;} }
  }
}

コントローラーPersonController.cs:

public ActionMethod Person(int id)
{
  var model = new PersonViewModel();
  model.Data = MyDataProvider.GetPersonById(id);
  model.MetaData = MyDataProvider.GetPersonMetaData(id);

  return View(model);
}

ビュー、Person.cshtml:

@using MyProject.Admin.Extensions

<h1>@Model.Data.GetFormattedName()</h1>
<img src="~/Images/People/image_@(Model.MetaData["image"]).png" >
<ul>
  <li>@Model.MetaData["comments"]</li>
  <li>@Model.MetaData["employer_comments"]</li>
</ul>
@Html.EditorFor(m => m.PersonDetails)
7
8DX

ベースファイルをリンクファイルとしてプロジェクトに追加します。それはまだ部分的ですが、両方のプロジェクト間で共有できるようにするため、それらを同期させ、同時に部分クラスにバージョン/フレームワーク固有のコードを保持します。

2
leon

おそらく静的拡張クラスを使用します。

1
Braneloc

これについても同様の問題がありました。 Dataプロジェクトに部分クラスを保持したため、「MyProject.Data」になります。 MetaDataClassesは管理プロジェクトに入れないでください。そうしないと、循環参照が作成されます。

MetaDataClasses用の新しいClass Libプロジェクトを追加しました。 「MyProject.MetaData」を使用し、これをデータプロジェクトから参照しました

1
Indy

新しいプロジェクトにリンクとしてクラスファイルを追加し、部分クラスに同じ名前空間を保持するだけです。

0
nl20121974

ここで間違っているかもしれませんが、MyProject.AdminプロジェクトでProjectMetaDataクラスを単純に定義することはできませんか?

0
Darragh