你应该在项目中使用部分类吗?

时间:2008-11-21 19:45:32

标签: c# partial-classes

我有一个包含所有数据库逻辑的类库。我的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
  }
}

使用相同的命名空间在单独的项目中创建一个部分类(创建一个依赖项)是个好主意吗?如果这是一个坏主意,我怎样才能使这种类型的功能起作用?

它似乎不想在编译时合并它们,所以我不确定我做错了什么。

8 个答案:

答案 0 :(得分:76)

您不能跨项目编写部分类。部分类是一个只编译时间的语法糖 - 整个类型最终都在一个程序集中,即一个项目。

(顺便说一下,你原来的DAL文件必须声明该类是偏的。)

答案 1 :(得分:5)

我无法回答关于组织图层的最佳方式的问题,但我可以尝试回答有关如何最好地模拟部分类的问题。

以下是一些想法:

  • 首先想到的是继承。它不一定是最好的解决方案,但您可能没有选择,因为您可能需要能够像对象一样对待您的对象。
  • 组合也是一个不错的选择(也就是说,将类包装在另一个类中)。这使您可以更好地与DAL脱钩,但实施起来可能很繁琐。
  • 如果您真的需要在现有类中添加一个或两个方法,您可能还会考虑使用extension method,但如果您使用它们,这些可以快速创建意大利面条代码。

答案 2 :(得分:4)

部分类必须存在于同一个程序集中。否则,编译器将如何决定将部分类合并到哪里?

答案 3 :(得分:4)

使用Visual Studio 2015及更高版本可以在项目之间拆分部分类:使用shared projects(另请参阅this MSDN blog)。

根据我的情况,我需要以下内容:

  • 一个类库,它定义了几个客户端应用程序用作接口的一些类。
  • 客户端应用程序。
  • 在数据库中创建表的设置应用程序 由于安装程序的限制,此设置必须是自包含的。它不能引用.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引用类库,共享项目:

<?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 :(得分:1)

我认为没有理由不采用这种方案:

两个文件包含存储机制(或其他一些功能)。它们指定继承但不包含业务逻辑:

  • ProductDataAccess.cs
  • ProductWeb.cs

一个文件包含业务逻辑:

  • ProductBusinessLogic.cs

现在创建两个项目:

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

两个项目都使用相同的业务逻辑。

答案 5 :(得分:0)

我同意Jon Skeet的回答。

我认为无论如何处理这样的问题都不是一个好的选择。有很好的设计模式已经证明了分割你的层/代码层的最佳方法,这只是一点点语法糖,因此微软可以将WinForms / WebForms设计器文件分开,防止人们破坏它们。 / p>

答案 6 :(得分:0)

虽然在谈到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时拆分图层/层的推荐方法。

答案 7 :(得分:0)

不可以。你不能在不同的项目中编写部分类。因为编译器只获得一个项目进行编译,因此只扫描该项目中的类,方法,字段等列表。所以如果你有一些部分的在其他项目中的部分类,编译器无法找到那些。