I have a class library with all my database logic. My DAL/BLL.
I have a few web projects which will use the same database and classes, so I thought it was a good idea to abstract the data layer into its own project.
However, when it comes to adding functionality to classes for certain projects I want to add methods to certain classes.
For example, my data layer has Product and SomeItem objects:
// Data Access Layer project namespace DAL { public class Product { //implementation here } public class SomeItem { //implementation here } }
In one project I want to add an interface that is used by different content items, so I have a class called:
// This is in Web Project namespace DAL { public partial class Product : ICustomBehaviour { #region ICustomBehaviour Implementation TheSharedMethod(); #endregion } }
Is it a good idea to write a partial class in a separate project (creating a dependency) using the same namespace? If it's a bad idea, how can I get this type of functionality to work?
It doesn't seem to want to merge them at compile time, so I'm not sure what I'm doing wrong.
Use of Partial ClassesIf you are working on a bigger project, splitting the files over different classes helps developers work on the same project simultaneously. If you are working on an automatically generated source, then the code can be added to the class without regenerating the source file.
Advantages of a partial classYou can separate UI design code and business logic code so that it is easy to read and understand. For example, you are developing a web application using Visual Studio and add a new web form then there are two source files, "aspx. cs" and "aspx. designer.
No, you cannot have two partial classes referring to the same class in two different assemblies (projects). Once the assembly is compiled, the meta-data is baked in, and your classes are no longer partial. Partial classes allows you to split the definition of the same class into two files.
Inheritance cannot be applied to partial classes.
You can't write a partial class across projects. A partial class is a compile-time-only piece of syntactic sugar - the whole type ends up in a single assembly, i.e. one project.
(Your original DAL file would have to declare the class to be partial as well, by the way.)
Using Visual Studio 2015 and later it is possible to split partial classes across projects: use shared projects (see also this MSDN blog).
For my situation I required the following:
The following example demonstrates how partial classes and shared projects allow splitting classes over different projects.
In Class Library, 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; } } }
Class Library is a normal Visual Studio Class Library. It imports the SharedProject, beyond that its .csproj contains nothing special:
<?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
is implemented in the SharedProject:
namespace SharedPartialCodeTryout.DataTypes { public partial class Address { public enum Direction { NORTH, EAST, SOUTH, WEST } } }
SharedProject.shproj is:
<?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>
And its .projitems is:
<?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>
The regular client uses Address
including 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}"); } } }
The regular client csproj references the Class Library and not 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>
The DbSetup uses only the enums:
The DbSetup.csproj does not reference Class Library; it only imports 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>
To conclude:
Can you split a partial class across projects?
Yes, use Visual Studio's Shared Projects.
Is it a good idea to write a partial class in a separate project (creating a dependency) using the same namespace?
Often not (see the other answers); in some situations and if you know what you are doing it can be handy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With