web-dev-qa-db-fra.com

Est-il possible que deux classes partielles dans des assemblages différents représentent la même classe?

J'ai une classe appelée "Article" dans un projet appelé "MyProject.Data", qui sert de couche de données pour mon application Web.

J'ai un projet distinct appelé "MyProject.Admin", qui est un système d'administration basé sur le Web pour afficher/modifier les données, et a été construit à l'aide de données dynamiques ASP.NET.

Fondamentalement, je veux étendre la classe Article, en utilisant une classe partielle, afin que je puisse augmenter l'une de ses propriétés avec un extenseur "UIHint", ce qui me permettra de remplacer la zone de texte multiligne normale par un contrôle FCKEdit.

Ma classe partielle et mon extenseur ressembleraient à ceci:

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

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

Maintenant, tout fonctionne correctement si la classe partielle se trouve dans le même projet que la classe partielle d'origine - c'est-à-dire le projet MyProject.Data.

Mais le comportement de l'interface utilisateur ne doit pas se situer dans la couche Données, mais plutôt dans la couche Admin. Je souhaite donc déplacer cette classe vers MyProject.Admin.

Cependant, si je fais cela, la fonctionnalité est perdue.

Ma question fondamentale est: puis-je avoir 2 classes partielles dans des projets séparés, mais les deux se référant à la même "classe"?

Sinon, existe-t-il un moyen d'accomplir ce que j'essaie de faire, sans mélanger la logique de la couche de données avec la logique de l'interface utilisateur?

122
Jonathan

Non, vous ne pouvez pas avoir deux classes partielles faisant référence à la même classe dans deux assemblys (projets) différents. Une fois l'assembly compilé, les métadonnées sont intégrées et vos classes ne sont plus partielles. Les classes partielles vous permettent de diviser la définition de la même classe en deux fichiers.

169
Darin Dimitrov

Comme indiqué, les classes partielles sont un phénomène de compilation, pas d'exécution. Les classes dans les assemblys sont par définition complètes.

En termes MVC, vous souhaitez conserver le code de vue distinct du code du modèle, tout en activant certains types d'interface utilisateur en fonction des propriétés du modèle. Découvrez l'excellent aperçu de Martin Fowler des différentes saveurs de MVC, MVP et ainsi de suite: vous trouverez de nombreuses idées de design. Je suppose que vous pouvez également utiliser Injection de dépendances pour indiquer à l'interface utilisateur quel type de contrôles sont viables pour les entités et les attributs individuels.

Votre objectif de séparer les préoccupations est grand; mais les classes partielles étaient destinées à résoudre des problèmes entièrement différents (principalement avec les langages de génération de code et de modélisation au moment de la conception).

13
Pontus Gagge

Les méthodes d'extension et ViewModels sont le moyen standard d'étendre des objets de couche de données dans le frontend comme ceci:

Couche de données (bibliothèque de classes, Person.cs):

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

Afficher la couche (application 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 (pour les données étendues spécifiques à la vue):

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;} }
  }
}

Contrôleur PersonController.cs:

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

  return View(model);
}

Vue, 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

Ajoutez le fichier de base en tant que fichier lié dans vos projets. C'est encore partiel mais comme cela vous permet de le partager entre les deux projets, de les garder synchronisés et en même temps d'avoir du code spécifique à la version/framework dans les classes partielles.

2
leon

Utilisez peut-être une classe d'extension statique.

1
Braneloc

J'ai eu des problèmes similaires avec cela. J'ai gardé mes classes partielles dans mon projet Data donc dans votre cas le 'MyProject.Data'. Les MetaDataClasses ne devraient pas entrer dans votre projet Admin car vous créerez une référence circulaire autrement.

J'ai ajouté un nouveau projet Class Lib pour mes MetaDataClasses, par exemple 'MyProject.MetaData', puis référencé cela à partir de mon projet Data

1
Indy

Ajoutez simplement le fichier de classe comme lien dans votre nouveau projet et conservez le même espace de noms dans votre classe partielle.

0
nl20121974

Je peux me tromper ici, mais ne pourriez-vous pas simplement définir la classe ProjectMetaData dans votre projet MyProject.Admin?

0
Darragh