【问题标题】:Inconsistent accessibility: return type is less than method可访问性不一致:返回类型小于方法
【发布时间】:2018-10-25 08:00:11
【问题描述】:

我知道inconsistent accessibility 的问题经常被问到,而我的问题不同,因为我需要它是私密的。

详细解释一下:我有一个staticLineLine中有一个structLingSegment,用户可以在Line中定义自己的LineSegment ,我需要确保线段之间没有冲突。

架构如下:

public static class Line {
    private struct LineSegment {
        public LineSegment(int start, int end) {
            Start = start;
            End = end;
        }

    public readonly int Start;
    public readonly int End;
    }

   // User created LineSegment
   static public LineSegment Segment1() {
       return new LineSegment(1, 2);
   }

   static public LineSegment Segment2() {
       return new LineSegment(3, 6);
   }
}

而当用户想要访问自己的线段时,只能访问如下:

int start = Line.Segment1.Start;
int end = Line.Segment1.End;

我将LineSegment设为private的原因是:我只想让用户通过Line中的静态函数来创建和访问LineSegment,例如Segment1Segment2。这样我就可以通过反射添加一个单元测试来获取Line中的所有方法,并获取所有线段的开始和结束,然后我可以判断线段之间是否存在冲突。

如果LineSegment 是公开的,用户可以使用new Line.LineSegment(2, 5) 破解他们的代码,而我无法通过单元测试检测到它。我不希望他们在Line 之外创建LineSegment

但在 C# 中不允许使用 LineSegment,因为 可访问性不一致。他们有什么解决方案可以满足我的要求吗?谢谢!

【问题讨论】:

  • 其实不然,其他人的代码在这个方案下还是可以直接构造LineSegment的。
  • 但是Segment1Segment2也不能构造LineSegment
  • 如果他们可以访问解决方案,他们可以简单地删除私有修饰符......我想:如果程序员做了愚蠢的事情,那么让他做愚蠢的事情......另一方面手 ... 为什么不让 LineSegment 构造函数采用 Line 参数,或者让工厂构建 LineSegments 并在运行时完成检查?
  • 是的,有。但是编译器说构造函数由于其保护级别而无法访问。我认为是因为无法调用私有构造函数?
  • 是的,你的评论很有道理。如果他们有权访问解决方案,他们可以简单地删除私有修饰符......但我认为不要给他们LineSegment 的访问权限会给他们使用Segment1 之类的功能的提示......(如果他们构造了LineSegment,我什至找不到!

标签: c# visibility


【解决方案1】:

怎么样:给他们访问权限但警告他们...

    public static class Line {
        public struct LineSegment {
            [Obsolete("DO NOT USE THIS DIRECTLY...")]
            public LineSegment(int start, int end) {
                Start = start;
                End = end;
            }

        public readonly int Start;
        public readonly int End;
        }

       // User created LineSegment
       static public LineSegment Segment1() {
           return _CreateSegment(1, 2);
       }

       static public LineSegment Segment2() {
           return _CreateSegment(3, 6);
       }

       static private LineSegment _CreateSegment(int start,int end) {
//we don't want to trigger the warning ...
#pragma warning disable 618
           return new LineSegment(3, 6);
#pragma warning restore 618
       }
    }

【讨论】:

  • 函数_CreateSegment也会触发一个警告,因为它的返回类型是LineSegment...
  • 整个方法禁用 618 有帮助吗?
  • 是的,它有帮助。但似乎并不美丽。
【解决方案2】:

在这些情况下,一个经过良好尝试的模式是定义一个公共接口并保持内部类私有,并使用公共(或内部)构造函数。通过这种方式,您可以防止在同一项目上工作的其他开发人员(甚至未来的您自己)直接调用构造函数,同时仍然允许他们访问类的相关属性。 所以,首先定义接口:

public interface ILineSegment
{
    int Start { get; }
    int End { get; }
}

然后是你的班级:

public static class Line
{
    private struct LineSegment : ILineSegment
    {
        public int Start { get; }
        public int End { get; }

        public LineSegment(int start, int end)
        {
            Start = start;
            End = end;
        }
    }

    // User created LineSegment
    static public ILineSegment Segment1()
    {
        return new LineSegment(1, 2);
    }

    static public ILineSegment Segment2()
    {
        return new LineSegment(3, 6);
    }

注意 LineSegment1 和 LineSegment2 的返回值由 LineSegment(私有,不能通过公共方法返回)改为 ILineSegment,公共的,可以返回。

【讨论】:

  • 是的,这是个好主意,但我认为DarkSquirrel42的想法可以避免增加一个接口,减少代码的变化。
【解决方案3】:

经过比较和征求意见,最后我选择使用Environment.StackTrace.Contains来满足我的要求。

public static class Line {
    public struct LineSegment {
        public LineSegment(int start, int end) {
            if (!Environment.StackTrace.Contains("MyNamespace.Line") || !Environment.StackTrace.Contains("UnitTest")) {
                throw new InvalidOperationException("Outside code is not allowed to call its constructor. Please construct your property in this file refering to the example.");
            }

            Start = start;
            End = end;
        }

        public readonly int Start;
        public readonly int End;
    }

   // User created LineSegment
   static public LineSegment Segment1() {
       return new LineSegment(1, 2);
   }

   static public LineSegment Segment2() {
       return new LineSegment(3, 6);
   }
}

【讨论】:

    猜你喜欢
    • 2019-05-14
    • 2021-01-16
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-07
    相关资源
    最近更新 更多