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

129

У меня есть класс под названием «Статья» в проекте под названием «MyProject.Data», который действует как уровень данных для моего веб-приложения.

У меня есть отдельный проект под названием «MyProject.Admin», который представляет собой веб-систему администрирования для просмотра / редактирования данных и был создан с использованием динамических данных ASP.NET.

В основном я хочу расширить класс 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, который специально отделяет модель от представления от контроллера, и вам нужна логика представления и проверки в классах данных. Rediculous. Должен быть лучший способ применения этих атрибутов. Вы должны иметь возможность связать класс метаданных с классом данных, используя свободный API или что-то подобное. Это не должно быть запеченным.
Джим
В некоторых других ответах упоминается это: если это абсолютно необходимо, и вы владеете ссылочным источником сборки, вы всегда можете включить исходные модели в качестве связанных файлов (кнопка разделения в средстве выбора файлов Add-Existing-Item), чтобы они были построены с потребляющая вместо сборки исх. (Аналогичная стратегия раскрытия уровня модели / данных через WCF с помощью ссылки на службу и расширения этих частичных классов, генерируемых кодом.) Вы никогда не будете вынуждены разбивать слои - вы всегда можете создать подкласс. И MetadataTypeделает модели более похожими на ViewModels.
JoeBrockhaus
Слишком поздно отвечать, но у меня есть решение здесь
Усман
Я знаю, что уже слишком поздно отвечать, но здесь я представил решение.
Усмань

Ответы:

178

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

Дарин Димитров
источник
15

Как уже отмечалось, частичные классы - это явление времени компиляции, а не времени выполнения. Классы в сборках по определению завершены.

В терминах MVC вы хотите сохранить код представления отдельно от кода модели, но при этом включить определенные виды пользовательского интерфейса на основе свойств модели. Ознакомьтесь с превосходным обзором Мартина Фаулера различных разновидностей MVC, MVP и еще много чего: вы найдете множество дизайнерских идей. Я полагаю, вы также можете использовать внедрение зависимостей, чтобы сообщить пользовательскому интерфейсу, какие элементы управления подходят для отдельных объектов и атрибутов.

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

Pontus Gagge
источник
8

Методы расширения и модели представления - это стандартный способ расширения объектов уровня данных во внешнем интерфейсе следующим образом:

Уровень данных (библиотека классов, 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)
8DX
источник
Комментарий Extensions имеет немало смысла, его можно полностью отделить от объекта Person с помощью интерфейса. Мне это нравится!
Pale Ale
2

Добавьте базовый файл как связанный файл в свои проекты. Он по-прежнему частичный, но позволяет вам делиться им между обоими проектами, поддерживать их синхронизацию и в то же время иметь код, специфичный для версии / платформы, в частичных классах.

Леон
источник
1

У меня были похожие проблемы с этим. Я сохранил свои частичные классы в моем проекте данных, поэтому в вашем случае MyProject.Data. Классы MetaDataClasses не должны входить в ваш проект администратора, так как иначе вы создадите циклические ссылки.

Я добавил новый проект Class Lib для своих MetaDataClasses, например MyProject.MetaData, а затем сослался на него из моего проекта данных

Инди
источник
1

Возможно использование статического класса расширения.

Braneloc
источник
Отличная идея. Можете ли вы привести пример того, что, по вашему мнению, обеспечит достаточную функциональность в вашем ответе?
pvanhouten
0

Я могу ошибаться здесь, но не могли бы вы просто определить класс ProjectMetaData в своем проекте MyProject.Admin?

Дарраг
источник
0

Просто добавьте файл класса в качестве ссылки в свой новый проект и сохраните то же пространство имен в частичном классе.

nl20121974
источник
0

С 2019 года вы можете иметь 2 части частичного класса в разных сборках, используя трюк. Этот трюк объясняется и демонстрируется в этой статье:

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

Он использует в своей основе расширение MSBuild.Sdk.Extras для SDK, такого как проекты, которое устраняет ограничение наличия всех частичных частей класса в одной сборке за счет использования одного проекта с несколькими одновременными целевыми объектами, эффективно создавая несколько сборок в одной компиляции. того же проекта.

Softlion
источник