Следует ли вам использовать частичный класс в разных проектах? - PullRequest
39 голосов
/ 21 ноября 2008

У меня есть библиотека классов со всей моей логикой базы данных. Мой DAL / BLL.

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

Однако, когда дело доходит до добавления функциональности к классам для определенных проектов, я хочу добавить методы к определенным классам.

Например, мой слой данных имеет объекты Product и SomeItem:

// Data Access Layer project

namespace DAL {
  public class Product { 
     //implementation here 
  }

  public class SomeItem {
     //implementation here 
  }
}

В одном проекте я хочу добавить интерфейс, который используется различными элементами контента, поэтому у меня есть класс с именем:

// This is in Web Project
namespace DAL {
  public partial class Product : ICustomBehaviour {

    #region ICustomBehaviour Implementation
       TheSharedMethod();
    #endregion
  }
}

Является ли хорошей идеей написать частичный класс в отдельном проекте (создание зависимости), используя то же самое пространство имен? Если это плохая идея, как я могу заставить этот тип функциональности работать?

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

Ответы [ 8 ]

76 голосов
/ 21 ноября 2008

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

(Кстати, ваш исходный файл DAL должен был бы также объявить класс частичным.)

5 голосов
/ 20 декабря 2008

Я не могу ответить на ваш вопрос о том, как лучше организовать ваши слои, но я могу попытаться ответить на ваш вопрос о том, как лучше всего эмулировать частичные классы.

Вот несколько мыслей:

  • Первое, что приходит на ум, - это наследование. Это не всегда лучшее решение всегда, но у вас может не быть выбора, поскольку вам может потребоваться, чтобы ваши объекты могли обрабатываться как базовый класс.
  • Композиция также является хорошим выбором (то есть, оборачивает класс в другой класс). Это дает вам более приятное разделение с вашим DAL, но может быть утомительным для реализации.
  • Если вам действительно нужно добавить метод или два в существующий класс, вы можете также рассмотреть возможность использования метода расширения , но это может быстро создать код спагетти, если вы используете их слишком часто. *
4 голосов
/ 16 января 2018

Используя Visual Studio 2015 и более поздние версии можно разделить частичные классы по проектам: используйте общие проекты (см. Также этот блог MSDN ).

Для моей ситуации мне потребовалось следующее:

  • Библиотека классов, которая определяет некоторые классы, используемые в качестве интерфейса несколькими клиентскими приложениями.
  • Клиентское приложение.
  • Приложение установки, которое создает таблицы в базе данных.
    Из-за ограничений установщика эта настройка должна быть автономной. Он не может ссылаться на какие-либо сборки за пределами .NET Framework. Программа установки должна вставить некоторые константы перечисления в таблицы, поэтому в идеале она должна ссылаться на библиотеку классов.
    Программа установки может импортировать общий проект.
  • Поскольку общий проект похож на копирование кода вставки, я хочу как можно меньше перемещаться в общий проект.

В следующем примере показано, как частичные классы и общие проекты позволяют разделять классы по разным проектам.

В библиотеке классов, Address.cs:

namespace SharedPartialCodeTryout.DataTypes
{
    public partial class Address
    {
        public Address(string name, int number, Direction dir)
        {
            this.Name = name;
            this.Number = number;
            this.Dir = dir;
        }

        public string Name { get; }
        public int Number { get; }
        public Direction Dir { get; }
    }
}

Библиотека классов - это обычная библиотека классов Visual Studio. Он импортирует SharedProject, за исключением того, что его .csproj не содержит ничего особенного:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
<!-- standard Visual Studio stuff removed -->
    <OutputType>Library</OutputType>
<!-- standard Visual Studio stuff removed -->
  </PropertyGroup>
<!-- standard Visual Studio stuff removed -->
  <ItemGroup>
    <Reference Include="System" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Address.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <Import Project="..\SharedProject\SharedProject.projitems" Label="Shared" />
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Address.Direction реализовано в SharedProject:

namespace SharedPartialCodeTryout.DataTypes
{
    public partial class Address
    {
        public enum Direction
        {
            NORTH,
            EAST,
            SOUTH,
            WEST
        }
    }
}

SharedProject.shproj:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Label="Globals">
    <ProjectGuid>33b08987-4e14-48cb-ac3a-dacbb7814b0f</ProjectGuid>
    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
  </PropertyGroup>
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
  <PropertyGroup />
  <Import Project="SharedProject.projitems" Label="Shared" />
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

И его .projitems:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
    <HasSharedItems>true</HasSharedItems>
    <SharedGUID>33b08987-4e14-48cb-ac3a-dacbb7814b0f</SharedGUID>
  </PropertyGroup>
  <PropertyGroup Label="Configuration">
    <Import_RootNamespace>SharedProject</Import_RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="$(MSBuildThisFileDirectory)Address.Direction.cs" />
  </ItemGroup>
</Project>

Обычный клиент использует Address, включая Address.Direction:

using SharedPartialCodeTryout.DataTypes;
using System;

namespace SharedPartialCodeTryout.Client
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create an Address
            Address op = new Address("Kasper", 5297879, Address.Direction.NORTH);
            // Use it
            Console.WriteLine($"Addr: ({op.Name}, {op.Number}, {op.Dir}");
        }
    }
}

Обычный клиент csproj ссылается на библиотеку классов, а не SharedProject:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
<!-- Removed standard Visual Studio Exe project stuff -->
    <OutputType>Exe</OutputType>
<!-- Removed standard Visual Studio Exe project stuff -->
  </PropertyGroup>
<!-- Removed standard Visual Studio Exe project stuff -->
  <ItemGroup>
    <Reference Include="System" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\SharedPartialCodeTryout.DataTypes\SharedPartialCodeTryout.DataTypes.csproj">
      <Project>{7383254d-bd80-4552-81f8-a723ce384198}</Project>
      <Name>SharedPartialCodeTryout.DataTypes</Name>
    </ProjectReference>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

DbSetup использует только перечисления:

DbSetup.csproj не ссылается на библиотеку классов; импортируется только SharedProject:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
<!-- Removed standard Visual Studio Exe project stuff -->
    <OutputType>Exe</OutputType>
<!-- Removed standard Visual Studio Exe project stuff -->
  <?PropertyGroup>
<!-- Removed standard Visual Studio Exe project stuff -->
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <Import Project="..\SharedProject\SharedProject.projitems" Label="Shared" />
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

В заключение:

Можете ли вы разделить частичный класс по проектам?

Да, используйте общие проекты Visual Studio.

Это хорошая идея написать частичный класс в отдельном проекте (создание зависимости), используя то же пространство имен?

Часто нет (см. Другие ответы); в некоторых ситуациях, и если вы знаете, что делаете, это может быть полезно.

4 голосов
/ 21 ноября 2008

Частичные классы должны существовать в одной сборке. Иначе как компилятор решит, куда объединить частичные классы?

1 голос
/ 11 марта 2011

Я не вижу причин, почему эта схема не будет работать:

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

  • ProductDataAccess.cs
  • ProductWeb.cs

Один файл содержит бизнес-логику:

  • ProductBusinessLogic.cs

Теперь создайте два проекта:

  • WebProject содержит ProductWeb.cs и ProductBusinessLogic.cs.
  • DataProject содержит ProductDataAccess.cs и ProductBusinessLogic.cs

В обоих проектах используется одна и та же бизнес-логика.

0 голосов
/ 22 мая 2014

Нет. Вы не можете писать частичные классы в разных проектах. Потому что за один раз компилятор получает один проект для компиляции и поэтому просматривает только список классов, методов, полей и т. Д. В этом проекте. частичный класс в других проектах, компилятор не может их найти.

0 голосов
/ 20 декабря 2008

Хотя я согласен с вами, Нил, когда дело доходит до разработки pre-linq, мне также хотелось бы иметь возможность сделать это, чтобы отделить бизнес-логику от частичных классов, сгенерированных конструктором Linq2SQL. Например:

Northind.DAL (prj)
-NorthindDataContext (EntityNamespace set to "Northwind.BLL")
--Product() (Entity, partial class auto-generated)
--Category() (Entity, partial class auto-generated)
--Supplier() (Entity, partial class auto-generated)

Northind.BLL (prj)
-Product() : IMyCustomEnityInterface, BaseEntity (override OnValidate(), etc)
-Category() : IMyCustomEnityInterface, BaseEntity (override OnValidate(), etc)
-Supplier() : IMyCustomEnityInterface, BaseEntity (override OnValidate(), etc)

К сожалению, мы не можем сделать это ... на самом деле я хотел бы знать, какой рекомендуемый способ разделения слоев / уровней при использовании LINQ.

0 голосов
/ 21 ноября 2008

Я согласен с ответом Джона Скита.

Не думаю, что в любом случае было бы хорошим решением подойти к такой проблеме. Уже есть хорошие шаблоны проектирования, которые демонстрируют лучший способ разделения ваших уровней / слоев кода, и это всего лишь небольшой синтаксический признак, чтобы Microsoft могла отделить файлы конструктора WinForms / WebForms и предотвратить их взлом. 1003 *

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...