Ist es möglich, dass zwei Teilklassen in verschiedenen Baugruppen dieselbe Klasse darstellen?

128

Ich habe eine Klasse namens "Artikel" in einem Projekt namens "MyProject.Data", die als Datenschicht für meine Webanwendung fungiert.

Ich habe ein separates Projekt namens 'MyProject.Admin', ein webbasiertes Administrationssystem zum Anzeigen / Bearbeiten der Daten, das mit ASP.NET Dynamic Data erstellt wurde.

Grundsätzlich möchte ich die Article-Klasse mithilfe einer Teilklasse erweitern, damit ich eine ihrer Eigenschaften mit einem "UIHint" -Extender erweitern kann, mit dem ich das normale mehrzeilige Textfeld durch ein FCKEdit-Steuerelement ersetzen kann.

Meine Teilklasse und mein Extender würden so aussehen:

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

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

Dies funktioniert nun einwandfrei, wenn sich die Teilklasse im selben Projekt wie die ursprüngliche Teilklasse befindet, dh im MyProject.Data-Projekt.

Das Verhalten der Benutzeroberfläche sollte jedoch nicht in der Datenebene, sondern in der Admin-Ebene liegen. Daher möchte ich diese Klasse nach MyProject.Admin verschieben.

Wenn ich das mache, geht die Funktionalität jedoch verloren.

Meine grundlegende Frage lautet: Kann ich zwei Teilklassen in separaten Projekten haben, aber beide beziehen sich auf dieselbe "Klasse"?

Wenn nicht, gibt es eine Möglichkeit, das zu erreichen, was ich versuche, ohne Datenschichtlogik mit UI-Logik zu mischen?

Jonathan
quelle
1
Genau deshalb stinkt das Konzept von MetadataType. ( en.wikipedia.org/wiki/Code_smell ). Es ist eine völlig fehlerhafte Lösung. Sie versuchen, eine MVC zu erstellen, die das Modell spezifisch von der Ansicht vom Controller trennt, und Sie benötigen eine Ansichts- und Validierungslogik in den Datenklassen. Lächerlich. Es sollte eine bessere Möglichkeit geben, diese Attribute anzuwenden. Sie sollten in der Lage sein, eine Metadatenklasse mithilfe einer fließenden API oder ähnlichem einer Datenklasse zuzuordnen. Es sollte nicht eingebrannt werden.
Jim
Einige andere Antworten erwähnen dies: Wenn es ein absolutes Muss ist und Sie die referenzierte Assembly-Quelle besitzen, können Sie die Quellmodelle immer als verknüpfte Dateien einschließen (Split-Button in der Dateiauswahl für vorhandene Elemente hinzufügen), damit sie mit dem erstellt werden Verbrauch statt Montage ref. (Eine ähnliche Strategie wie das Offenlegen Ihrer Modell- / Datenschicht über WCF mit einer Dienstreferenz und das Erweitern dieser Klassen mit partiellem Code.) Sie sind niemals gezwungen, Ebenen zu zerschlagen - Sie können jederzeit Unterklassen erstellen. Und MetadataTypemacht Models eher zu ViewModels.
JoeBrockhaus
Es ist zu spät, um zu antworten, aber ich habe hier eine Lösung bereitgestellt
Usman
Ich weiß, dass es zu spät ist, um zu antworten, aber hier habe ich eine Lösung vorgestellt.
Usman

Antworten:

178

Nein, Sie können nicht zwei Teilklassen haben, die sich auf dieselbe Klasse in zwei verschiedenen Assemblys (Projekten) beziehen. Sobald die Assembly kompiliert ist, werden die Metadaten eingebrannt und Ihre Klassen sind nicht mehr partiell. Mit Teilklassen können Sie die Definition derselben Klasse in zwei Dateien aufteilen.

Darin Dimitrov
quelle
15

Wie bereits erwähnt, sind Teilklassen ein Phänomen zur Kompilierungszeit und keine Laufzeit. Klassen in Baugruppen sind per Definition vollständig.

In MVC-Begriffen möchten Sie den Ansichtscode vom Modellcode trennen und dennoch bestimmte Arten von Benutzeroberflächen basierend auf den Modelleigenschaften aktivieren. Schauen Sie sich Martin Fowlers hervorragenden Überblick über die verschiedenen Geschmacksrichtungen von MVC, MVP und so weiter an: Sie werden jede Menge Designideen finden. Ich nehme an, Sie können auch Dependency Injection verwenden , um der Benutzeroberfläche mitzuteilen, welche Steuerelemente für einzelne Entitäten und Attribute geeignet sind.

Ihr Ziel, Bedenken zu trennen, ist groß. Teilklassen sollten jedoch ganz andere Probleme angehen (hauptsächlich mit Codegenerierung und Modellierungssprachen zur Entwurfszeit).

Pontus Gagge
quelle
8

Erweiterungsmethoden und ViewModels sind die Standardmethode zum Erweitern von Datenebenenobjekten im Frontend wie folgt:

Datenschicht (Klassenbibliothek, Person.cs):

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

Anzeigeebene (Webanwendung) 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 (für erweiterte ansichtsspezifische Daten):

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

Controller PersonController.cs:

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

  return View(model);
}

Ansicht, 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)
8DX
quelle
Der Kommentar "Erweiterungen" ist sehr sinnvoll. Er kann mithilfe einer Schnittstelle vollständig vom Objekt "Person" entkoppelt werden. Ich mag das!
Pale Ale
2

Fügen Sie die Basisdatei als verknüpfte Datei zu Ihren Projekten hinzu. Es ist immer noch teilweise, aber da Sie es für beide Projekte freigeben können, halten Sie sie synchron und haben gleichzeitig version- / Framework-spezifischen Code in den Teilklassen.

Leon
quelle
1

Ich hatte ähnliche Probleme damit. Ich habe meine Teilklassen in meinem Datenprojekt behalten, also in Ihrem Fall die 'MyProject.Data'. MetaDataClasses sollten nicht in Ihr Admin-Projekt aufgenommen werden, da Sie auf andere Weise Zirkelverweise erstellen.

Ich habe ein neues Class Lib-Projekt für meine MetaDataClasses hinzugefügt, z. B. 'MyProject.MetaData', und dieses dann aus meinem Datenprojekt referenziert

Indy
quelle
1

Verwenden Sie möglicherweise eine statische Erweiterungsklasse.

Braneloc
quelle
Gute Idee. Können Sie ein Beispiel dafür geben, was Ihrer Meinung nach in Ihrer Antwort eine ausreichende Funktionalität bietet?
pvanhouten
0

Ich kann mich hier irren, aber könnten Sie nicht einfach die ProjectMetaData-Klasse in Ihrem MyProject.Admin-Projekt definieren?

Darragh
quelle
0

Fügen Sie einfach eine Klassendatei als Link in Ihr neues Projekt ein und behalten Sie den gleichen Namespace in Ihrer Teilklasse bei.

nl20121974
quelle
0

Seit 2019 können Sie mit einem Trick 2 Teile einer Teilklasse in verschiedenen Baugruppen haben. Dieser Trick wird in diesem Artikel erklärt und demonstriert:

https://www.notion.so/vapolia/Secret-feature-Xamarin-Forms-control-s-auto-registration-1fd6f1b0d98d4aabb2defa0eb14961fa

Im Kern wird die Erweiterung MSBuild.Sdk.Extras für SDK-ähnliche Projekte verwendet, mit der die Einschränkung behoben wird, dass alle Teilteile einer Klasse in derselben Assembly enthalten sind, indem ein Projekt mit mehreren gleichzeitigen Zielen verwendet wird, wodurch effektiv mehrere Assemblys in einer Kompilierung erstellt werden des gleichen Projekts.

Softlion
quelle