不同命名空间中的部分类

81

我能在不同的命名空间中创建部分类吗?它会正常工作吗? 例如:

class1.cs

namespace name1
{
    public partial class Foo
    {
        Bar1(){
            return 10;
        }
    }
}

class2.cs

namespace name1.name2
{
    public partial class Foo
    {
        Bar2(){
            return 100;
        }
    }
}

main.cs

using name1;
using name1.name2;

namespace mainClass
{
    public class mainClass
    {
        Foo classFoo = new Foo();
        int Count = classFoo.Bar1() + classFoo.Bar2();
        // Will Count = 110?
    }
}

如果我的示例不正确,我应该做些什么才能使其正常工作?

7个回答

107
一个类的名称包括它的命名空间,因此name1.Fooname1.name2.Foo是两个完全不同的类型。所以回答你的问题是:不行。 你为什么需要做这样的事情?

我想制作单独的库。以在不修改主类的情况下添加新功能。 我对这个主题有很大的疑问... - RAMe0
9
我建议两种可能性。第一种是在name1.name2.Foo中为name1.Foo创建一个子类。第二种是使用扩展方法(http://msdn.microsoft.com/en-us/library/bb383977.aspx),这是一种很好的方法,可以“添加”功能到您不控制或者由于某些原因不想修改的类中。 - CodingGorilla
4
部分类是在编译时解析的,.NET框架中没有部分类的概念,它只是一种语言结构。它允许一个类的源代码在编译期间出现在多个源文件中。请注意,这不会影响最终生成的程序集中的类的结构。 - AnthonyWJones
我刚想到一件事...如果我创建项目并将它们命名为"Name1.n2"、"Name1.n3"、"Name1.n4"等,但使用一个命名空间和部分类,那么dll的名称会是"Name1.n2"、"Name1.n3"等吗?我能像示例文档中那样使用它吗? - RAMe0
为什么我需要这样做:我有根据 WSDL 规范生成的类。我希望使用 Entity Framework 持久化它们,以防客户端失败并且稍后必须重试...这需要类具有 Id 属性。我不想在生成的命名空间中创建部分类。 - Pétur Ingi Egilsson
显示剩余2条评论

35

部分类仅能在同一命名空间和同一程序集中实现。

命名空间可以分布在两个不同的程序集中,但是部分类则不能。


19
以下是在实现部分类时需要考虑的一些要点:
- 在每个部分中使用 partial 关键字。 - 部分类的每个部分名称应相同,但每个部分所在的源文件名称可以不同。 - 所有部分都应位于同一个命名空间中。 - 部分类的每个部分应该在同一个程序集或 DLL 中,换句话说,不能在不同类库项目的源文件中创建部分类。 - 部分类的每个部分具有相同的可访问性(如 private、public 或 protected)。 - 如果在部分类上继承了一个类或接口,则它将被继承到部分类的所有部分。 - 如果部分类的某个部分是 sealed,则整个类将被视为 sealed 类。 - 如果部分类的某个部分是 abstract,则整个类将被视为抽象类。
参考链接:C# 中的部分类

7

这样做是行不通的。编译器会在Foo classFoo = new Foo();这一行给你一个模糊名称错误。为了让部分类起作用,它们必须位于同一命名空间中,因为命名空间实际上是类型的完全限定名称的一部分。


1
我理解这个,这就是为什么我在问...请阅读先前答案的评论。 - RAMe0
@Coding Gorilla的评论是正确的。如果您只想向类型添加方法,那么要么子类化(如果类型未密封),要么使用扩展方法是可行的方法。 - Harry Steinhilber

5
此外,对于静态类,您可以借助C# 6.0的新特性“using static”实现以下内容。请参考:使用 C# 6 中的静态 using 语句
例如:
namespace SomeLogic1
{
    public static class Util
    {
        public static int Bar1()
        {
            return 1;
        }
    }
}

namespace SomeLogic2
{
    public static class Util
    {
        public static int Bar2()
        {
            return 2;
        }
    }
}

namespace GeneralStuff
{
    using SomeLogic1;
    using SomeLogic2;

    public class MainClass
    {
        public MainClass()
        {
            // Error CS0104
            // 'Util' is an ambiguous reference between 'SomeLogic1.Util' and 'SomeLogic2.Util'
            var result = Util.Bar1() + Util.Bar2(); 
        }
    }
}  

这段代码无法编译,错误信息很明显。为了解决这个问题,你可以直接指定命名空间(但据我所知你不想这样做):

namespace GeneralStuff
{
    public class MainClass
    {
        public MainClass()
        {
            var result = SomeLogic1.Util.Bar1() + SomeLogic2.Util.Bar2(); 
        }
    }
}

或者,您可以使用静态特性进行申请,方法如下:

namespace GeneralStuff
{
    using static SomeLogic1.Util;
    using static SomeLogic2.Util;

    public class MainClass
    {
        public MainClass()
        {
            var result = Bar1() + Bar2(); 
        }
    }
}

也许对于一些辅助/工具类来说这样做是可以的。但是其他人已经注意到,部分类不是正确的方式。

2

1
我假设您的主要目标是在不同的命名空间中分发方法,否则这将是微不足道的(将所有内容放在一个类中,无论是否为部分类,您就完成了)。
所以假设的目标是:
  • 在命名空间name1中拥有2个方法Bar1和在命名空间name1.name2中拥有Bar2
  • 能够在一个类ClsFoo的上下文中调用上述任何一个方法
您不能使用部分类来实现此目的,但可以通过不同的方式实现:如果您使用扩展方法并将它们绑定到特定类,例如ClsFoo,那么您可以执行以下操作:
using SomeOtherNamespace;
using name1;
using name1.name2;

namespace mainClass
{
    public static class mainClass
    {
        public static void Main()
        {
            var classFoo = new ClsFoo();
            var count = classFoo.Bar1() + classFoo.Bar2();
            Console.WriteLine($"count = {count}"); // output is 110
        } // main               
    } // class
} // namespace

namespace SomeOtherNamespace
{
    public class ClsFoo
    {
        // does not need to contain any code
    } // class
} // namespace

namespace name1
{
    public static class FooExt
    {
        public static int Bar1(this ClsFoo foo)
        {
            return 10;
        } // method
    } // class
} // namespace

namespace name1.name2
{
    public static class FooExt
    {
        public static int Bar2(this ClsFoo foo)
        {
            return 100;
        } // method
    } // class
} // namespace

在线运行

这种方式,您声明了一个空的类ClsFoo,然后编写一些扩展方法Bar1()Bar2(),它们驻留在不同的命名空间和静态扩展类中。

注意: 扩展类可以具有相同的名称FooExt,只要它们位于不同的命名空间中,当然如果您喜欢,也可以给它们不同的名称,如FooExt1FooExt2 - 这个例子仍然有效;即使在较旧版本的C#中也是如此。


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