C# - 覆盖 System 命名空间中某些可用的类

5

我有一个项目需要在Compact .NET Framework 3.5和.NET Framework 3.5中进行编译(实际上是两个项目,只是编译选项在两者之间变化)。

问题是,CF .NET中缺少一些类,因此我手动创建了这些类(并实现了在.NET中可用的所有成员)。

例如:FtpWebRequest / FtpWebResponse类。

写下类似这样的东西很糟糕(为什么?):

#if CFNET35 // Only if we are in Compact Framework 3.5 mode
namespace System.Net
{
    public class FtpWebRequest : WebRequest
    {
        // ...
    }

    public class FtpWebResponse : WebResponse
    {
        // ...
    }
}
#endif

我确定在CF.NET35中这些方法永远不会可用,那么我可以写吗?
为了避免在项目中使用我的库时出现名称冲突,我会这样写。
这使我在其他项目中始终可以使用`using System.Net;`而不必问我使用哪个框架...
谢谢!
几个月后,我需要评估我使用的策略。
如上所述,我通过条件编译覆盖了System(.Net)命名空间,因此我有两个DLL(一个用于CF.NET,另一个用于.NET)
这也包括所有使用此DLL的应用程序都是成双的(每次一个CF.NET应用程序和一个包含相应库的.NET应用程序)。
所以,这是一个坏主意,我有很多重复的项目,这在某种程度上是不必要的,因为.NET应用程序可以直接包含和使用CF.NET库。
此外,我没有考虑到的一件事是,如果.NET应用程序包含带有重写的System命名空间的CF.NET库,则其初始化将失败,因为存在类名称冲突...
因此,EPIC FAIL,提供通用接口是管理此情况的最佳方法。

因为一些我不了解的做法或原因,我只是确保写这个不会造成太大的混乱。 - Arnaud F.
2
好的,未来不会再有另一个CF版本,所以它不会在未来出现问题。但是如果您将它们放在自己的程序集中,这就非常不必要了。 - Hans Passant
@Hans:你说“但是如果你把它们放在自己的程序集中,这就非常不必要了”,你有具体的例子吗? - Arnaud F.
4个回答

6
我建议您避免使用System命名空间来编写自定义代码。我曾见过一些开源库试图这样做,但通常会导致麻烦。
您最好创建一个在完整框架和紧凑框架之间共享的接口,然后在完整框架和CF中实现该接口,使用内置的System类或您自己编写的类提供所需的功能。
这可能看起来有点过度,但如果System.Net发生了变化,您将更加安全。您的调用代码应该只引用接口,然后根据您所在的平台插入任一实现。
// Shared interface
public interface IFtpUtil
{
    SomeFileObject GetFile(SomeArgument a);
    void PutFile(SomeFileObject f, SomeArgument a);
}

// Full framework implementation
public class FullFtpUtil : IFtpUtil
{
    public ... GetFile(...)
    {
        // Use System.Net classes from full framework
    }

    public ... PutFile(...)
    {
        // Use System.Net classes from full framework
    }
}

// Compact framework implementation
public class CompactFtpUtil : IFtpUtil
{
    public ... GetFile(...)
    {
        // Use your own FTP classes
    }

    public ... PutFile(...)
    {
        // Use your own FTP classes
    }
}

真是个过度设计啊... 我不仅有 FTP 部分,还有网络和电池管理。如果“明天”我删除 CF 部分,所有部分都将基于接口,重构代码以删除无用代码将不容易完成... - Arnaud F.
虽然看起来有些过度,但如果你随着时间将现有代码重构为基于接口的模式,我敢打赌你的类最终会变得更加清晰易于维护。我仍然建议不要在自定义代码中使用System命名空间。 - Andy White
我编辑了我的问题并进行了评估。从一开始你就是对的,抱歉大师;-) - Arnaud F.

5

我不会这样做,不是因为有任何具体的技术原因,而是因为这可能会导致一些严重的混淆。没有人希望自定义类驻留在System命名空间中。

System命名空间中的类经过了广泛的测试和许多人的使用,所以如果你团队中的其他人在他们的代码中使用System.Net.FtpWebRequest并且他们的代码不起作用,他们将(并且应该)首先搜索自己代码中的错误。经过多个小时的搜索,当他们发现错误实际上在内置的系统类中时,他们会对你感到愤怒。


我同意你的观点,但对于CF.NET实现,我有很多跟踪记录,并且所有应用程序都将由同一团队开发(他们知道如何覆盖系统方法)。因此,我认为时间损失(如果有的话)不会太大。我们可以自己调试它,这是事实。 - Arnaud F.
2
将它放在你自己的命名空间中,只有在定义了CFNET35时才进行“using”。 - user7116

2

我意识到我对这个问题来得太晚了,但是我认为我可以添加一些价值,因为我们经常做这样的事情。SDF可能有50%的填充物适用于与桌面框架匹配的类。我们所做的是使用我们自己的名称空间。所以让我们以Ftp为例。我们会这样做:

namespace OpenNETCF.Net

public class FtpWebRequest  { ... }

消费者应用程序将使用别名来解决这个问题:
#if NETCF
using FtpWebRequest = OpenNETCF.Net.FtpWebRequest;
#else
using FtpWebRequest = System.Net.FtpWebRequest;
#endif

void Foo()
{
    // the alias above resolves these for you
    // enabling a single, fairly clean code base
    var request = new FtpWebRequest(...);
}

0

遇到过类似情况。想要使用一些在WinForms框架中提供的命名空间/类,但却被移除了移动框架。

我建议不要将您的命名空间放在“system”命名空间中,而是尽可能设计您的代码与框架相似,除非您的应用程序需要特定的附加功能。

using system;

// "sysmobile" emulates code for the "system" namespace

namespace sysmobile {
  class FtpWebRequest { ... }
  class FtpWebResponse { ... }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接