Совместное использование кода C# между классами

StackOverflow https://stackoverflow.com/questions/1878419

  •  18-09-2019
  •  | 
  •  

Вопрос

Как лучше всего распределить код между несколькими классами и исходными файлами в Visual Studio 2008 с использованием C#?

Наследование не является решением, поскольку классы уже имеют значимую иерархию.

Есть ли какая-нибудь изящная функция, похожая на включаемый файл C, которая позволяет вставлять код в любое место другого класса?

РЕДАКТИРОВАТЬ:

ок, думаю, нам нужен конкретный пример...

В домене несколько сотен классов с хорошо продуманной иерархией классов.Теперь многие из этих классов необходимо распечатать.Существует класс служебного принтера, который управляет печатью.Допустим, есть 3 разных метода печати, которые зависят от печатаемого класса.Код, вызывающий метод печати (6 строк), — это то, что я пытаюсь избежать копирования и вставки на все страницы различных клиентских классов.

Было бы неплохо, если бы люди не предполагали, что они знают больше о предметной области, чем операция, особенно когда они конкретно упоминают методы, которые не подходят...

Это было полезно?

Решение

Если у вас есть функциональные возможности, которые вы часто используете в классах, представляющих совершенно разные вещи, по моему опыту, их следует разделить всего на несколько категорий:

  • Утилиты (напр.форматирование строк, синтаксический анализ, ...)
  • Сквозные проблемы (ведение журнала, обеспечение безопасности и т. д.)

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

public class Validator
{
  public bool IsValidName(string name);
}

class Patient
{
  private Validator validator = new Validator();
  public string FirstName
  {
     set
     {
         if (validator.IsValidName(value)) ... else ...
     }
  }
}

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

Что касается PrintA против.Пример PrintB, обсуждаемый в других комментариях, звучит как отличный пример шаблона Factory.Вы определяете интерфейс, например.IPrint — классы PrintA и PrintB, которые реализуют IPrint и назначают экземпляр IPrint в зависимости от потребностей конкретной страницы.

// Simplified example to explain:

public interface IPrint 
{ 
   public void Print(string); 
}

public class PrintA : IPrint
{
   public void Print(string input)
   { ... format as desired for A ... }
}

public class PrintB : IPrint
{
   public void Print(string input)
   { ... format as desired for B ... }
}

class MyPage
{
   IPrint printer;

   public class MyPage(bool usePrintA)
   {
      if (usePrintA) printer = new PrintA(); else printer = new PrintB();
   }

   public PrintThePage()
   {
      printer.Print(thePageText);
   }
}

Другие советы

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

Однако вы можете определить интерфейс и объявить методы расширения для этого интерфейса.Затем интерфейс может быть реализован вашими классами, и вы сможете вызывать методы расширения этих классов.Например.

public interface IShareFunctionality { }

public static class Extensions
{
    public static bool DoSomething(this IShareFunctionality input)
    {
        return input == null;
    }
}

public class MyClass : Object, IShareFunctionality
{
    public void SomeMethod()
    {
        if(this.DoSomething())
            throw new Exception("Impossible!");
    }
}

Это позволит вам повторно использовать функциональность, но вы не сможете получить доступ к закрытым членам класса, как если бы вы могли, скажем, включить в хэш файл.

Возможно, нам понадобятся более конкретные примеры того, что вы хотите сделать?

Утилитный класс C# будет работать.Он действует как центральный реестр для общего кода (или как конструкция модуля VB.NET) — он должен содержать код, не специфичный для какого-либо класса, в противном случае его следовало бы прикрепить к соответствующему классу.

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

Если источнику не требуется сохранять состояние, используйте статический класс со статическим методом.

static public class MySharedMembers {
    static public string ConvertToInvariantCase(string str)  {
        //...logic
    }
    // .... other members
}

Если классы находятся в одном пространстве имен, аналог включения не нужен.Просто вызовите члены класса, определенные в другой функции.

Если они не находятся в одном пространстве имен, добавьте пространство имен классов, которые вы хотите использовать, в директивах using, и оно должно работать так же, как указано выше.

Меня смущает вопрос:кажется, вам нужно поработать над базовым пониманием объектно-ориентированного подхода.

Методы расширения кассы: http://msdn.microsoft.com/en-us/library/bb383977.aspx

Я не знаю, как включить части файлов, но мы часто делаем одну вещь: добавляем существующий файл и «связываем» его с текущим местоположением.Например, у нас есть файл AssemblyInfo.cs, на который ссылается каждый проект из каталога решения.Мы изменяем его один раз, и все проекты будут иметь одинаковую информацию, поскольку они ссылаются на один и тот же файл.

В противном случае предложения по рефакторингу «общих» процедур в common.dll — лучшее, что я придумал в .Net.

Я уже не совсем понимаю, что вы подразумеваете под «значимой» структурой, но это похоже на место, где вы могли бы использовать реализацию базового класса.Хотя это и не так «подробно», как множественное наследование в C++, вы можете получить некоторую выгоду от использования реализации связанного базового класса для повторного использования общих функций.

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

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

Например, создайте PrintingService, который содержит логику, необходимую для печати.Затем вы можете сделать так, чтобы классы, которые необходимо печатать, зависели от этой службы (либо через конструктор, либо через параметр в методе, которому требуется служба).

Еще один совет, который у меня есть в этом отношении, — создавать интерфейсы для базовой функциональности, а затем использовать интерфейсы для написания кода.Например, у меня было несколько классов отчетов, которые пользователь мог отправить по факсу, электронной почте или распечатать.Вместо того, чтобы создавать методы для каждого, я создал для каждого сервис, и они реализовали интерфейс с единственным методом Output().Затем я мог бы передать каждую службу одному и тому же методу в зависимости от того, какой результат хочет получить пользователь.Когда клиент захотел использовать eFax вместо отправки факсов через модем, оставалось просто написать новую службу, реализующую тот же интерфейс.

Честно говоря, я не могу придумать ничего подобного включению в Visual C# и зачем вам эта функция.Тем не менее, частичные классы могут делать что-то вроде того, что вы хотите, но их использование может противоречить вашему требованию «классы уже имеют значимую иерархию».

У вас есть много вариантов: TT, метод расширения, делегат и лямбда.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top