È possibile avere due classi parziali in assiemi diversi che rappresentano la stessa classe?


128

Ho una classe chiamata 'Article' in un progetto chiamato 'MyProject.Data', che funge da layer di dati per la mia applicazione web.

Ho un progetto separato chiamato "MyProject.Admin", che è un sistema di amministrazione basato sul web per la visualizzazione / modifica dei dati, ed è stato creato utilizzando ASP.NET Dynamic Data.

Fondamentalmente voglio estendere la classe Article, usando una classe parziale, in modo da poter aumentare una delle sue proprietà con un extender "UIHint", che mi permetterà di sostituire la normale casella di testo multilinea con un controllo FCKEdit.

La mia classe parziale ed extender sarebbe simile a questa:

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

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

Ora tutto funziona bene se la classe parziale si trova nello stesso progetto della classe parziale originale, ovvero il progetto MyProject.Data.

Ma il comportamento dell'interfaccia utente non dovrebbe trovarsi nel livello dati, ma piuttosto nel livello amministratore. Quindi voglio spostare questa classe su MyProject.Admin.

Tuttavia, se lo faccio, la funzionalità viene persa.

La mia domanda fondamentale è: posso avere 2 classi parziali in progetti separati, ma entrambi riferiti alla stessa "classe"?

In caso contrario, c'è un modo per realizzare ciò che sto cercando di fare, senza mescolare la logica del livello dati con la logica dell'interfaccia utente?


1
Questo è esattamente il motivo per cui il concetto di MetadataType puzza. ( en.wikipedia.org/wiki/Code_smell ). È una soluzione completamente imperfetta: stai cercando di creare MVC che separa in modo specifico il modello dalla vista dal controller e hai bisogno della logica di visualizzazione e convalida nelle classi di dati. Ridicolo. Dovrebbe esserci un modo migliore per applicare questi attributi. Dovresti essere in grado di associare una classe di metadati a una classe di dati usando un'API fluente o qualcosa di simile. Non dovrebbe essere cotto.
Jim,

Alcune altre risposte menzionano questo: se è un must assoluto e possiedi l'origine dell'assembly di riferimento, puoi sempre includere i modelli di origine come file collegati (pulsante diviso nel selettore di file Aggiungi elemento esistente) in modo che vengano creati con il consumando al posto del montaggio rif. (Strategia simile per esporre il proprio livello Modello / Dati tramite WCF con un riferimento di servizio ed estendere quelle classi parziali generate da codice). Non si è mai costretti a distruggere i livelli - è sempre possibile effettuare una sottoclasse. E MetadataTyperende i modelli più simili a ViewModels.
JoeBrockhaus,

È troppo tardi per rispondere, ma ho fornito una soluzione qui
Usman,

So che è troppo tardi per rispondere, ma qui ho presentato una soluzione.
Usman,

Risposte:


178

No, non è possibile avere due classi parziali che si riferiscono alla stessa classe in due assiemi (progetti) diversi. Una volta compilato l'assembly, i metadati vengono inseriti e le classi non sono più parziali. Le classi parziali consentono di dividere la definizione della stessa classe in due file.


15

Come notato, le classi parziali sono un fenomeno in fase di compilazione, non di runtime. Le classi negli assiemi sono per definizione complete.

In termini MVC, si desidera mantenere il codice di visualizzazione separato dal codice del modello, ma abilitare determinati tipi di UI in base alle proprietà del modello. Dai un'occhiata all'eccellente panoramica di Martin Fowler sui diversi gusti di MVC, MVP e quant'altro: troverai idee di design in abbondanza. Suppongo che tu possa anche usare Dependency Injection per dire all'interfaccia utente che tipo di controlli sono praticabili per le singole entità e attributi.

Il tuo obiettivo di separare le preoccupazioni è grande; ma le classi parziali dovevano affrontare questioni completamente diverse (principalmente con la generazione del codice e i linguaggi di modellazione in fase di progettazione).


8

I metodi di estensione e ViewModels sono il modo standard per estendere gli oggetti del livello dati nel frontend in questo modo:

Livello dati (libreria di classi, Person.cs):

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

Display Layer (applicazione 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 (per dati specifici della vista estesa):

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

Visualizza, 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)

Il commento sulle estensioni ha un bel po 'di senso, questo può essere completamente disaccoppiato dall'oggetto Person usando un'interfaccia. Mi piace!
Pale Ale,

2

Aggiungi il file di base come file collegato nei tuoi progetti. È ancora parziale ma ti consente di condividerlo tra entrambi i progetti, di mantenerli sincronizzati e allo stesso tempo di avere codice specifico versione / framework nelle classi parziali.


1

Ho avuto problemi simili con questo. Ho tenuto le mie lezioni parziali nel mio progetto Data, quindi nel tuo caso il "MyProject.Data". MetaDataClasses non dovrebbe andare nel tuo progetto di amministrazione in quanto creerai riferimenti circolari in altro modo.

Ho aggiunto un nuovo progetto Class Lib per i miei MetaDataClasses, ad esempio "MyProject.MetaData" e quindi ho fatto riferimento a questo dal mio progetto Data


1

Forse usa una classe di estensione statica.


Buona idea. Puoi fornire un esempio di ciò che pensi possa fornire una funzionalità sufficiente nella tua risposta?
pvanhouten,

0

Potrei sbagliarmi qui, ma non potresti semplicemente definire la classe ProjectMetaData nel tuo progetto MyProject.Admin?


0

Basta aggiungere il file di classe come collegamento nel nuovo progetto e mantenere lo stesso spazio dei nomi nella classe parziale.


0

Dal 2019 puoi avere 2 parti di una classe parziale in diversi assiemi usando un trucco. Questo trucco è spiegato e dimostrato in questo articolo:

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

Utilizza al suo interno l'estensione MSBuild.Sdk.Extras a progetti simili a SDK, che risolve la limitazione di avere tutte le parti parziali di una classe nello stesso assieme, utilizzando un progetto con più destinazioni simultanee, creando efficacemente più assiemi in una raccolta dello stesso progetto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.