简体   繁体   English

通过C#中的属性公开对象

[英]Exposing objects through properties in C#

I want to write a static utility class which only has a set of properties, which expose functionality to the user 我想编写一个静态实用程序类,它仅具有一组属性,这些属性向用户公开

For example I could call: 例如,我可以打电话给:

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

or 要么

Utils.Stream.CopyBytes(instream, outstream);

The closest thing I could liken this to is System.Text.Encoding where there are properties like UTF8, ASCII etc, so yo can call things like: 我最喜欢的是System.Text.Encoding,其中存在诸如UTF8,ASCII等属性,因此您可以调用以下内容:

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

or 要么

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

The problem is that in Encoding, this calls the equivalent objects ( UTF8Encoder , ASCIIEncoder ) which are publicly available to the user. 问题在于,在编码中,这将调用等效的对象( UTF8EncoderASCIIEncoder ),这些对象对用户是公开可用的。 What I want is to expose the objects ONLY via Utils, without visibilty of the objects that relate to the properties, for example 我想要的是仅通过实用工具公开对象,而无需查看与属性相关的对象,例如

I could call: 我可以打电话给:

Utils.Stream.CopyStream(instream, outstream);

but I could not call: 但我无法致电:

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

Is this possible, and if it is, is it going to be good or bad practice to do so? 这是否可能,如果可能,这样做是好事还是坏事?

Here's an idea: 这是一个主意:

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; }
    }
}

To me, however, this is somewhat of a strange practice. 但是,对我而言,这有点奇怪。 Personally I prefer extension methods for utility functionality: 我个人更喜欢实用程序功能的扩展方法:

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

which can also be considered bad, especially taking into account extension method discovery and resolution algorithms. 这也可以认为是不好的,特别是考虑到扩展方法发现和解析算法。 Good ol' StreamUtil.Copy() is just fine for most cases. 好的StreamUtil.Copy()在大多数情况下都很好。

It is not possible to prevent any user from creating a variable of your StreamUtils type and eg assigning the value retrieved from your Utils.Stream property. 无法阻止任何用户创建您的StreamUtils类型的变量,例如分配从Utils.Stream属性检索的值。

However, there are two solutions: 但是,有两种解决方案:

  1. You can prevent users from creating instances of your StreamUtils class themselves by making the constructor internal . 您可以通过使构造函数成为internal来阻止用户自己创建StreamUtils类的实例。 Like that, only your Utils class (to which you can grant internal access, be it by placing it in the same assembly or by using the InternalsVisibleTo attribute ) can instantiate your StreamUtils class, while users of your library can only use the functions of your instance, but cannot create their own instance. 这样,只有您的Utils类(您可以授予内部访问权限,可以通过将其放置在同一程序集中或通过使用InternalsVisibleTo属性来进行访问 )可以实例化StreamUtils类,而库的用户只能使用您的函数。实例,但无法创建自己的实例。

  2. Another approach is using public nested static classes. 另一种方法是使用公共嵌套静态类。 Within your Utils class, you could declare a nested public static class Stream that offers the methods you need as static methods. 在您的Utils类中,您可以声明一个嵌套的公共静态类Stream ,该类提供所需的方法作为静态方法。 Like this, users could not instantiate their own Stream instance (as it's static), and at least in C#, you would even force users to always write Utils.Stream to access your methods, if that is what you really want. 这样,用户无法实例化自己的Stream实例(因为它是静态的),至少在C#中,您甚至会强制用户始终编写Utils.Stream来访问您的方法(如果您确实Utils.Stream Note, however, that this approach does not seem as clean as the first one and will cause breaking changes (at least on the binary level), should you ever decide to exchange the static classes with property getters or anything else. 但是请注意,如果您决定用属性获取器或其他任何方法交换静态类,则此方法似乎不像第一种方法干净,并且会导致重大更改(至少在二进制级别)。

What you want is possible, but you shouldn't see Utils as a class itself, but as a namespace that contains some static utility classes: 所需的功能是可能的,但您不应将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)
        {
            ...
        }
    }
}

Whether this is a recommended practice or not, is a completely different issue. 是否建议这样做,是完全不同的问题。 The problem with too many static utility classes, is that you can't have loose coupling by using dependency injection. 静态实用程序类太多的问题是,使用依赖项注入不能使耦合松散。 This can make it harder to write good unit tests. 这会使编写良好的单元测试变得更加困难。

Looking at what you are trying to achieve, I suggest, try and develop extention methods. 考虑到您要实现的目标,我建议尝试并开发扩展方法。

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. 扩展方法使您可以将方法“添加”到现有类型,而无需创建新的派生类型,重新编译或修改原始类型。 Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. 扩展方法是一种特殊的静态方法,但是它们的调用就像是扩展类型上的实例方法一样。

Read more on the hyperlink provided here . 此处提供的超链接上阅读更多内容。

Ok, basically it's no possible (in C# at least) to achieve exactly what I want. 好的,基本上不可能(至少在C#中)完全达到我想要的目标。 The class must be visible for the functionality to be visible through the Util class. 该类必须是可见的,才能通过Util类看到其功能。

My solution was to turn the classes (eg StreamUtils , StringUtils ) into singletons. 我的解决方案是将类(例如StreamUtilsStringUtils )转换为单例。 They cannot be constructed because their constructors are internal. 由于其构造函数是内部的,因此无法构造它们。 their methods are public but can never be seen because the object cannot be instantiated outside of my assembly. 它们的方法是公共的,但由于无法在程序集外部实例化该对象而无法看到。 The Utils class exposes the functionality to the user via the singleton instance. Utils类通过单例实例向用户公开功能。

Consider the following: 考虑以下:

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;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM