Чи можливо, щоб два часткові класи в різних складах представляли один клас?


128

У мене є клас під назвою "Article" у проекті під назвою "MyProject.Data", який виступає як рівень даних для мого веб-додатку.

У мене є окремий проект під назвою "MyProject.Admin", який є веб-системою адміністрування для перегляду / редагування даних, і був створений за допомогою ASP.NET Dynamic Data.

В основному я хочу розширити клас Article, використовуючи частковий клас, щоб я міг доповнити одну з його властивостей розширенням "UIHint", що дозволить мені замінити звичайне багаторядкове текстове поле на керування FCKEdit.

Мій частковий клас та розширювач виглядатиме так:

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

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

Тепер це все працює добре, якщо частковий клас знаходиться в тому ж проекті, що і вихідний частковий клас - тобто проект MyProject.Data.

Але поведінка інтерфейсу не повинна знаходитись у шарі даних, а скоріше на рівні адміністратора. Тому я хочу перенести цей клас на MyProject.Admin.

Однак якщо я це зробити, функціональність втрачається.

Моє основне питання: чи можу я мати 2 часткові класи в окремих проектах, але обидва стосуються одного і того ж «класу»?

Якщо ні, чи є спосіб зробити те, що я намагаюся зробити, не змішуючи логіку рівня даних з логікою інтерфейсу?


1
Саме тому смердить концепція MetadataType. ( en.wikipedia.org/wiki/Code_smell ). Це абсолютно недосконале рішення - Ви намагаєтеся побудувати MVC, який спеціально відокремлює модель від подання від контролера, і вам потрібна логіка перегляду та перевірки в класах даних. Слідкуючи. Повинен бути кращий спосіб застосування цих атрибутів. Ви повинні мати можливість пов’язати клас метаданих із класом даних за допомогою вільного API або чогось подібного. Її не слід запікати.
Джим

Деякі інші відповіді згадують це: Якщо це абсолютна необхідність, і ви володієте посиланням на джерело збірки, ви завжди можете включати моделі джерела у вигляді пов'язаних файлів (розділена кнопка на інструменті вибору файлів Add-Existing-Item), щоб вони були побудовані за допомогою споживання замість складання ref. (Аналогічна стратегія розкриття шару «Модель / Дані» через WCF з посиланням на службу та розширення цих парціальних класів з кодовим кодом.) Ви ніколи не змушені розбивати шари - ви завжди можете підкласи. І MetadataTypeробить моделі більш схожими на ViewModels.
JoeBrockhaus

Занадто пізно відповідати, але я маю надати рішення тут
Усман

Я знаю, що це занадто пізно, щоб відповісти, але ось я представив рішення.
Усман

Відповіді:


178

Ні, у вас не може бути двох часткових класів, що стосуються одного класу, у двох різних збірках (проектах). Після складання збірки метадані випікаються, і ваші класи вже не часткові. Часткові класи дозволяють розділити визначення одного класу на два файли.


15

Як зазначалося, часткові класи - це явище часу компіляції, а не час виконання. Класи в зборах за визначенням завершені.

Згідно з умовами MVC, ви хочете, щоб код перегляду був окремим від коду моделі, але ввімкнув певні види інтерфейсу на основі властивостей моделі. Перевірте відмінний огляд Мартіна Фаулера щодо різних ароматів MVC, MVP та іншого: ви знайдете достатньо дизайнерських ідей. Я припускаю, що ви також можете використовувати Dependency Injection, щоб сказати користувальницькому інтерфейсу, які елементи управління життєздатні для окремих об'єктів та атрибутів.

Ваша мета відокремити проблеми є великою; але часткові класи були призначені для вирішення зовсім інших питань (в першу чергу з генерування коду та мод моделювання в часі дизайну).


8

Методи розширення та ViewModels - це стандартний спосіб розширення об'єктів рівня даних у прямому інтервалі таким чином:

Шар даних (бібліотека класів, Person.cs):

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

Відображувальний шар (веб-додаток) 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)

Коментар розширень має досить багато сенсу, це можна повністю від'єднати від об'єкта Person за допомогою інтерфейсу. Мені це подобається!
Блідий Але

2

Додайте базовий файл як пов'язаний файл у свої проекти. Він все ще частковий, але як дозволяє поділитися ним між обома проектами, зберігати їх синхронізовано і одночасно мати специфічний код версії / рамки в часткових класах.


1

У мене були подібні проблеми з цим. Я зберігав часткові заняття в проекті "Дані", тому у вашому випадку "MyProject.Data". MetaDataClasses не повинен працювати у вашому адміністративному проекті, оскільки ви створите циркулярні посилання інших розумних.

Я додав новий проект Class Lib для своїх MetaDataClasses, наприклад, "MyProject.MetaData", а потім посилався на це зі свого проекту даних


1

Можливо, використовувати клас статичного розширення.


Гарна ідея. Чи можете ви навести приклад того, що, на вашу думку, забезпечить достатню функціональність у вашій відповіді?
pvanhouten

0

Я можу тут помилятися, але чи не могли ви просто визначити клас ProjectMetaData у вашому проекті MyProject.Admin?


0

Просто додайте файл класу як посилання у своєму новому проекті та зберігайте те саме простір імен у вашому частковому класі.


0

З 2019 року ви можете мати 2 частини часткового класу в різних складах, використовуючи трюк. Ця хитрість пояснюється і демонструється в цій статті:

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

У своїй основі він використовує розширення MSBuild.Sdk.Extras на проекти SDK, подібні до проектів, яке вирішує обмеження наявності всіх часткових частин класу в одній збірці, використовуючи один проект з декількома одночасними цілями, ефективно створюючи кілька збірок в одній компіляції того ж проекту.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.