簡體   English   中英

你應該在項目中使用部分類嗎?

[英]Should you use a partial class across projects?

我有一個包含所有數據庫邏輯的類庫。 我的DAL / BLL。

我有一些Web項目將使用相同的數據庫和類,所以我認為將數據層抽象到自己的項目中是一個好主意。

但是,當為某些項目的類添加功能時,我想向某些類添加方法。

例如,我的數據層有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
  }
}

使用相同的命名空間在單獨的項目(創建依賴項)中編寫部分類是一個好主意嗎? 如果這是一個壞主意,我怎樣才能使這種類型的功能工作?

它似乎不想在編譯時合並它們,所以我不確定我做錯了什么。

您不能跨項目編寫部分類。 部分類是一個僅編譯時間的語法糖 - 整個類型最終在一個程序集中,即一個項目。

(順便說一下,你的原始DAL文件也必須聲明該類是部分的。)

我無法回答關於組織圖層的最佳方法的問題,但我可以嘗試回答有關如何最好地模擬部分類的問題。

以下是一些想法:

  • 首先想到的是繼承。 它不一定是最好的解決方案,但您可能沒有選擇,因為您可能需要能夠像對象一樣對待您的對象。
  • 組合也是一個不錯的選擇(也就是說,將類包裝在另一個類中)。 這使您可以更好地與DAL分離,但實現起來可能很繁瑣。
  • 如果您真的只需要在現有類中添加一個或兩個方法,您可能還會考慮使用擴展方法 ,但如果您使用它們太多,這些方法可以快速創建意大利面條代碼。

部分類必須存在於同一個程序集中。 否則,編譯器將如何決定將部分類合並到哪里?

使用Visual Studio 2015及更高版本,可以跨項目拆分部分類:使用共享項目 (另請參閱此MSDN博客 )。

對於我的情況,我需要以下內容:

  • 一個類庫,它定義了一些由多個客戶端應用程序用作接口的類。
  • 客戶端應用程序。
  • 在數據庫中創建表的安裝應用程序。
    由於安裝程序的限制,此設置必須是自包含的。 它不能引用.NET框架之外的任何程序集。 設置應該將一些枚舉常量插入到表中,因此理想情況下它應該引用類庫。
    設置可以導入共享項目。
  • 由於共享項目與復制粘貼代碼類似,因此我希望盡可能少地移動到共享項目中。

以下示例演示了部分類和共享項目如何允許在不同項目上拆分類。

在類庫中,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的共享項目。

使用相同的命名空間在單獨的項目(創建依賴項)中編寫部分類是一個好主意嗎?

通常不會(見其他答案); 在某些情況下,如果你知道你在做什么,它可以很方便。

我認為這個方案沒有理由不起作用:

兩個文件包含存儲機制(或其他一些功能)。 它們指定繼承但不包含業務邏輯:

  • ProductDataAccess.cs
  • ProductWeb.cs

一個文件包含業務邏輯:

  • ProductBusinessLogic.cs

現在創建兩個項目:

  • WebProject包含ProductWeb.cs和ProductBusinessLogic.cs。
  • DataProject包含ProductDataAccess.cs和ProductBusinessLogic.cs

兩個項目都使用相同的業務邏輯。

不可以。你不能在不同的項目中編寫部分類。因為在編譯器獲取單個項目進行編譯時,只掃描該項目中的類,方法,字段等列表。所以如果你有部分類的部分其他項目,編譯器無法找到那些。

我同意Jon Skeet的回答。

無論如何,我認為處理這樣​​的問題不是一個好的選擇。 有很好的設計模式已經證明了分割你的層/代碼層的最佳方法,這只是一點點語法糖,因此微軟可以將WinForms / WebForms設計器文件分開,防止人們破壞它們。

雖然在談到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時分割圖層/層的推薦方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM