【问题标题】:Exposing objects through properties in C#通过 C# 中的属性公开对象
【发布时间】:2012-08-03 15:27:34
【问题描述】:

我想编写一个静态实用程序类,它只有一组属性,向用户公开功能

例如我可以调用:

Utils.String.GetHexString("Hello World");

Utils.Stream.CopyBytes(instream, outstream);

我可以把它比作最接近的东西是 System.Text.Encoding,其中有 UTF8、ASCII 等属性,所以你可以调用类似的东西:

Encoding.UTF8.GetBytes("Hello World");

Encoding.ASCII.GetBytes("Hello World");

问题在于,在编码中,这会调用对用户公开可用的等效对象(UTF8EncoderASCIIEncoder)。我想要的是仅通过 Utils 公开对象,而不显示与属性相关的对象,例如

我可以打电话:

Utils.Stream.CopyStream(instream, outstream);

但我不能打电话:

StreamUtils.CopyStream(instr, outstr) //This class is only accessible via the Utils class!

这是否可能,如果可以,这样做是好还是坏?

【问题讨论】:

  • 如果它是您自己的库,您可以在您的方法中使用internal 范围,因此只有在程序集中您才能访问那些较低级别的成员。如果您需要在库中的其他程序集中公开它,请使用 [InternalsVisibleTo] 属性。在你想向图书馆的消费者公开的接口上使用public,在你不想公开的接口上使用internal
  • 嗨,克里斯,感谢您的建议。我将研究 InternalVisible 属性,因为我以前没有使用过它,但它可能是我的王牌!

标签: c# .net properties utilities scoping


【解决方案1】:

这是一个想法:

public interface IStreamUtil
{
    void CopyStream(Stream int, Stream out);
}

internal class StreamUtil : IStreamUtil
{
    // Implementation
}

public static class Util
{
    private static IStreamUtil stream = new StreamUtil();
    public static IStreamUtil Stream 
    {
        get { return stream; }
    }
}

然而,对我来说,这有点奇怪。我个人更喜欢实用功能的扩展方法:

inStream.CopyStreamTo(outStream);
myString.GetHexString();

这也被认为是不好的,特别是考虑到扩展方法发现和解析算法。好的 ol' StreamUtil.Copy() 在大多数情况下都很好。

【讨论】:

  • 嗨安东。感谢您的建议,但是使用接口不是我想要的方式,因为这仍然会向用户暴露一些东西。提供实现/契约的所有东西都必须是不可见的,除了通过实用程序类中的属性。在使用扩展方法方面,我已经对此进行了研究,但到目前为止一直被阻止,因为这可能会使相关类型与很少使用的实用程序混淆(并且也会使智能感知看起来很混乱)。无论如何,感谢您的意见(投票++)
【解决方案2】:

无法阻止任何用户创建StreamUtils 类型的变量,例如分配从您的 Utils.Stream 属性中检索到的值。

但是,有两种解决方案:

  1. 您可以通过创建构造函数internal 来阻止用户自己创建StreamUtils 类的实例。像这样,只有您的 Utils 类(您可以授予内部访问权限,无论是通过将其放在同一个程序集中还是使用 InternalsVisibleTo attribute)可以实例化您的 StreamUtils 类,而您的库的用户只能使用您的实例的功能,但不能创建自己的实例。

  2. 另一种方法是使用公共嵌套静态类。在您的Utils 类中,您可以声明一个嵌套的公共静态类Stream,它提供您需要的静态方法。像这样,用户不能实例化他们自己的 Stream 实例(因为它是静态的),至少在 C# 中,你甚至会强制用户总是写 Utils.Stream 来访问你的方法,如果那是你真正想要的。但是请注意,如果您决定将静态类与属性 getter 或其他任何东西交换,这种方法似乎不如第一种方法干净,并且会导致重大更改(至少在二进制级别上)。

【讨论】:

    【解决方案3】:

    您想要的都是可能的,但您不应该将Utils 视为一个类本身,而应将其视为一个包含一些静态实用程序类的命名空间:

    namespace Utils
    {
        public static class String
        {
            public static string GetHexString(string input)
            {
                ...
            }
        }
    
        public static class Stream
        {
            public static void CopyBytes(System.IO.Stream instream, System.IO.Stream outstream)
            {
                ...
            }
        }
    }
    

    这是否是推荐的做法,是一个完全不同的问题。太多静态实用程序类的问题在于,您不能通过使用依赖注入来实现松散耦合。这会使编写好的单元测试变得更加困难。

    【讨论】:

      【解决方案4】:

      看看你想要达到的目标,我建议,尝试开发extention methods.

      扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,但它们被称为扩展类型的实例方法。

      阅读更多关于here提供的超链接。

      【讨论】:

        【解决方案5】:

        好的,基本上不可能(至少在 C# 中)完全实现我想要的。该类必须是可见的,功能才能通过 Util 类可见。

        我的解决方案是将类(例如StreamUtilsStringUtils)变成单例。它们不能被构造,因为它们的构造函数是内部的。他们的方法是公开的,但永远无法看到,因为无法在我的程序集之外实例化该对象。 Utils 类通过单例实例向用户公开功能。

        考虑以下几点:

        class StreamUtils
        {
            static StreamUtils instance;
        
            internal static StreamUtils Instance
            {
                get
                {
                    if(instance == null)
                    {
                        instance = new StreamUtils();
                    }
                    return instance;
                }
            }
        
            internal StreamUtils()
            {
            }
        
            public void CopyStream(Stream input, Stream output)
            {
            }
        }
        
        static class Utils
        {
            public StreamUtils Stream
            {
                get
                {
                     return StreamUtils.Instance;
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-29
          • 1970-01-01
          • 2011-10-03
          • 2016-05-05
          • 1970-01-01
          • 2010-11-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多