8

在使用 C# 的 Visual Studio 2008 中,跨多个类和源文件共享代码的最佳方式是什么?

继承不是解决方案,因为类已经具有有意义的层次结构。

是否有一些类似于 C 包含文件的简洁功能可以让您在另一个类中的任何位置插入代码?

编辑:

好的,我想我们需要一个具体的例子......

该域中有数百个类具有经过深思熟虑的类层次结构。现在,其中许多类需要打印。有一个处理打印的实用程序打印机类。假设有 3 种不同的打印方法取决于正在打印的类。调用 print 方法的代码(6 行)是我试图避免在所有不同的客户端类页面之间复制和粘贴的代码。

如果人们不认为他们对操作的领域有更多的了解,那就太好了——尤其是当他们特别提到不适合的技术时……

4

10 回答 10

8

如果您有在代表非常不同事物的类中经常使用的功能,根据我的经验,它应该分为几类:

  • 实用程序(例如字符串格式化、解析等)
  • 横切关注点(日志记录、安全实施……)

对于实用程序类型的功能,您应该考虑创建单独的类,并在业务类中需要的地方引用实用程序类。

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 示例,这听起来像是工厂模式的绝佳案例。您定义一个接口,例如 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);
   }
}
于 2009-12-10T03:49:51.540 回答
7

您不能像在 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!");
    }
}

这将允许您重用功能,但您无法访问类的私有成员,如果您可以,例如,散列包含一个文件,您将能够访问。

我们可能需要一些更具体的例子来说明您想要做什么?

于 2009-12-10T03:24:42.387 回答
3

AC# 实用程序类将起作用。它就像公共代码的中央注册表(或像 VB.NET 模块结构)——它应该包含不特定于任何类的代码,否则它应该附加到相关类。

如果您不需要,您不想开始复制源代码,因为考虑到重复,这会导致代码更新问题。

只要源不需要保留状态,则使用带有静态方法的静态类。

static public class MySharedMembers {
    static public string ConvertToInvariantCase(string str)  {
        //...logic
    }
    // .... other members
}
于 2009-12-10T03:15:21.223 回答
2

如果这些类在同一个命名空间中,则不需要包含模拟。只需调用在另一个函数中定义的类的成员。

如果它们不在同一个命名空间中,请在 usings 指令中添加要使用的类的命名空间,它应该与上述相同。

我对这个问题感到困惑:您似乎需要了解基本的 OO 知识。

于 2009-12-10T03:18:56.113 回答
2

结帐扩展方法:http: //msdn.microsoft.com/en-us/library/bb383977.aspx

于 2009-12-10T03:19:56.033 回答
2

我不知道包含部分文件的方法,但我们经常做的一件事是添加现有文件并从其当前位置“链接”它。例如,我们有一个 assemblyInfo.cs 文件,每个项目都从解决方案目录引用该文件。我们更改一次,所有项目都具有相同的信息,因为它们引用的是同一个文件。

否则,关于在 common.dll 中重构“通用”例程的建议是我在 .Net 中提出的最佳建议。

于 2009-12-10T03:45:09.380 回答
1

我已经不确定你所说的“有意义的”结构是什么意思,但这听起来像是一个你可以使用基类实现的地方。虽然不像 C++ 多重继承那样“冗长”,但您可能会从使用链式基类实现来重用常用函数中获得一些好处。

您可以至少在视觉上保留类层次结构并根据需要覆盖行为。

于 2009-12-10T03:22:01.020 回答
1

将重复的代码提取到服务中。重复的代码暗示可能有一些重构空间。

例如,创建一个包含打印所需逻辑的“PrintingService”。然后,您可以让需要打印的类依赖于该服务(通过构造函数或需要该服务的方法中的参数)。

我在这些方面的另一个技巧是为基本功能创建接口,然后使用这些接口进行编码。例如,我有一堆报告类,用户可以使用传真、电子邮件或打印。我没有为每个创建方法,而是为每个创建一个服务,让它们实现一个接口,该接口具有一个 Output() 方法。然后,我可以根据用户想要的输出类型将每个服务传递给相同的方法。当客户想要使用 eFax 而不是通过调制解调器发送传真时,只需编写一个实现相同接口的新服务即可。

于 2009-12-10T04:37:45.003 回答
0

老实说,我想不出像 Visual C# 中的包含之类的东西,也想不出你为什么想要那个特性。也就是说,部分类可以做一些听起来像你想要的事情,但是使用它们可能会与你的“类已经有一个有意义的层次结构”的要求发生冲突。

于 2009-12-10T03:17:07.537 回答
0

你有很多选项,TT、扩展方法、委托和 lambda

于 2009-12-10T03:32:18.340 回答