Question

J'ai une bibliothèque de classes avec toute la logique de ma base de données. Mon DAL / BLL.

J'ai quelques projets Web qui utiliseront la même base de données et les mêmes classes, alors j’ai pensé que c’était une bonne idée d’abréger la couche de données dans son propre projet.

Cependant, lorsqu'il s'agit d'ajouter des fonctionnalités aux classes de certains projets, je souhaite ajouter des méthodes à certaines classes.

Par exemple, ma couche de données contient des objets Product et SomeItem:

// Data Access Layer project

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

  public class SomeItem {
     //implementation here 
  }
}

Dans un projet, je souhaite ajouter une interface utilisée par différents éléments de contenu. J'ai donc une classe appelée:

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

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

Est-ce une bonne idée d'écrire une classe partielle dans un projet séparé (créant une dépendance) en utilisant l'espace de noms identique ? Si c'est une mauvaise idée, comment puis-je utiliser ce type de fonctionnalité?

Il ne semble pas vouloir les fusionner au moment de la compilation, je ne suis donc pas sûr de ce que je fais de mal.

Était-ce utile?

La solution

Vous ne pouvez pas écrire une classe partielle sur plusieurs projets. Une classe partielle est un morceau de sucre syntaxique réservé à la compilation. Tout le type se termine en un seul assemblage, c’est-à-dire un projet.

(D'ailleurs, votre fichier DAL d'origine devrait également déclarer la classe partielle).

Autres conseils

Je ne peux pas répondre à votre question sur la meilleure façon d'organiser vos couches, mais je peux essayer de répondre à votre question sur la meilleure façon d'émuler des classes partielles.

Voici quelques réflexions:

  • La première chose qui nous vient à l’esprit est l’héritage. Ce n’est pas forcément toujours la meilleure solution, mais vous n’avez peut-être pas le choix, car vous devrez peut-être pouvoir traiter vos objets de la même manière que la classe de base.
  • La composition est également un bon choix (c’est-à-dire que la classe est enveloppée dans une autre classe). Cela vous donne un découplage un peu plus agréable de votre DAL, mais peut être fastidieux à mettre en œuvre.
  • Si vous avez simplement besoin d'ajouter une ou deux méthodes à une classe existante, vous pouvez également envisager d'utiliser un méthode d’extension , mais elles peuvent rapidement créer du code spaghetti si vous les utilisez trop.

Les classes partielles doivent exister dans le même assemblage. Sinon, comment le compilateur déciderait-il où fusionner les classes partielles?

À l'aide de Visual Studio 2015 et versions ultérieures , il est possible de fractionner des classes partielles entre plusieurs projets: utilisez projets partagés (voir aussi ce blog MSDN ).

Pour ma situation, j'avais besoin des éléments suivants:

  • Une bibliothèque de classes qui définit certaines classes utilisées comme interface par plusieurs applications clientes.
  • L'application cliente.
  • Une application d'installation qui crée des tables dans la base de données.
    En raison des limitations de l'installateur, cette configuration doit être autonome. Il ne peut référencer aucun assemblage au-delà du framework .NET. La configuration doit insérer des constantes d’énumération dans les tables, elle doit donc idéalement faire référence à la bibliothèque de classes.
    La configuration peut importer un projet partagé.
  • Un projet partagé est semblable au code copier-coller. Je souhaite donc déplacer le moins possible dans le projet partagé.

L'exemple suivant montre comment des classes partielles et des projets partagés autorisent le fractionnement de classes sur différents projets.

Dans la bibliothèque de classes, 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; }
    }
}

La bibliothèque de classes est une bibliothèque de classes Visual Studio normale. Il importe le SharedProject, au-delà de son .csproj ne contient rien de spécial:

<?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 est implémenté dans le projet partagé:

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

SharedProject.shproj est:

<?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>

Et son .projitems est:

<?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>

Le client standard utilise Adresse , y compris Adresse.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(
<?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>
quot;Addr: ({op.Name}, {op.Number}, {op.Dir}"); } } }

Le client standard csproj référence la bibliothèque de classes et non 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>

DbSetup utilise uniquement les enums:

Le fichier DbSetup.csproj ne fait pas référence à la bibliothèque de classes; il importe uniquement SharedProject:

<*>

Pour conclure:

  

Pouvez-vous diviser une classe partielle entre plusieurs projets?

Oui, utilisez les projets partagés de Visual Studio.

  

Est-ce une bonne idée d'écrire une classe partielle dans un projet séparé (en créant une dépendance) en utilisant le même espace de nom?

Souvent pas (voir les autres réponses); dans certaines situations et si vous savez ce que vous faites, cela peut être pratique.

Je ne vois pas pourquoi ce système ne fonctionnerait pas:

Deux fichiers contiennent des mécanismes de stockage (ou une autre fonctionnalité). Ils spécifient l'héritage mais ne contiennent aucune logique métier:

  • ProductDataAccess.cs
  • ProductWeb.cs

Un fichier contient la logique applicative:

  • ProductBusinessLogic.cs

Créez maintenant deux projets:

  • WebProject contient ProductWeb.cs et ProductBusinessLogic.cs.
  • DataProject contient ProductDataAccess.cs et ProductBusinessLogic.cs

Les deux projets utilisent la même logique métier.

Je suis d'accord avec la réponse de Jon Skeet.

Je ne pense pas que ce serait un bon choix d’aborder un problème comme celui-là de toute façon. Il existe déjà de bons modèles de conception qui démontrent le meilleur moyen de scinder vos niveaux / couches de code. Il ne s'agit que d'un petit sucre syntaxique permettant à Microsoft de séparer les fichiers du concepteur WinForms / WebForms et d'empêcher les utilisateurs de les décomposer.

Bien que je sois d’accord avec vous pour le développement pré-linq, Neil, je souhaiterais également pouvoir le faire afin de séparer la logique de gestion des classes partielles générées par le concepteur Linq2SQL. Par exemple:

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)

Malheureusement, nous ne pouvons pas faire cela ... j'aimerais en fait savoir quelle est la méthode recommandée pour diviser les couches / niveaux en utilisant LINQ.

Non. Vous ne pouvez pas écrire de classes partielles dans différents projets.Parce que le compilateur obtient un seul projet pour la compilation, il scanne la liste des classes, méthodes, champs, etc. de ce projet uniquement. Ainsi, si vous avez des parties du classe partielle dans d’autres projets, le compilateur ne peut pas les trouver.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top