【问题标题】:Restrict access to public properties of partial class限制对部分类的公共属性的访问
【发布时间】:2016-08-26 01:52:15
【问题描述】:

上下文

我有一个自动生成的部分类,其中一些公共属性表示来自其他嵌套模型的数据。例如。有床的房间:

// Auto-generated class from DB schema
public partial class HotelRoom : BaseModel
{
    public int RoomNumber {get; set;}
    public string BedKind {get; set;}
    public int BedSize {get; set;}
    public bool BedHasBlankets {get; set;}

    // Methods and more DB-related logic here
}

问题

我想将嵌套模型(在本例中为)的数据封装在单个对象中,但限制对容器模型中表示它的属性的访问(酒店客房)。

// Suppose we get a reference to a HotelRoom
HotelRoom room = HotelRoom.GetFromDB(someNumber);

// I want this to be valid ...
var size = room.Bed.Size;

// ...but this to be invalid
var size = room.BedSize;

无效是指我希望它导致编译错误,但如果根本不可能,则抛出警告,甚至阻止 BedSize 出现在 IntelliSense 中(例如使用 [Browsable (false)]属性)可能几乎和我想要的一样好。

我目前的做法

目前,我可以使用嵌套类来实现这一点,但我希望代码禁止或至少警告程序员不要使用某些自动生成的公共属性。例如

// My own partial class
public partial class HotelRoom : BaseModel
{
    // Here I would like to make BedKind, BedSize and BedHasBlankets private
    // or make something that has a similar effect as making them private

    // Then I can encapsulate those variables in this object whose class
    // has access to the private properties of HotelRoom, since it's nested
    private Bed bed;
    public Bed Bed
    {
      get
      {
        if(bed == null)
        {
          bed = new Bed(this);
        }
        return bed;
      }
    }

    public class Bed
    {
      private HotelRoom container;
      public string Kind { get{ return container.BedKind } }
      public int Size { get{ return container.BedSize } }
      // Maybe perform some data transformation:
      public bool NeedsBlankets { get{ return !container.BedHasBlankets;} }

      public Bed(HotelRoom container)
      {
        this.container = container
      }
}

我为什么要这个?

我知道你可能会想,我到底为什么想要这样的东西。好吧,在我的现实生活场景中,一些自动生成的公共属性的名称并不像 room.BedSize 那样简短直观,而是像:obj.DeviceManufacturerManufacturerTypeId 这样我认为使用类似 @ 的名称会更清楚。 987654328@.

TL;DR:

如何在部分类中将某些在同一部分类的另一个(自动生成)部分中定义为公共的属性设为私有? 如果这不可能,我怎样才能达到类似的效果?

【问题讨论】:

  • 我认为您必须包装自动生成的类,而不是使用 partial 扩展它。
  • 您是否可以简单地将属性设为私有 (private int RoomNumber {get; set;}),因为您打算通过嵌套类访问它们? (或者你不能控制类的生成?)
  • @Yvette:一个项目,我需要使用由自定义 ORM 生成的模型,该模型读取我无法修改的数据库架构并根据表和列名称生成模型。
  • @AlexeiLevenkov 我无法控制类的生成。我想请 ORM 的开发人员允许我决定生成模型的访问修饰符,但我不能指望这一点。

标签: c# .net visual-studio


【解决方案1】:

让您的自动生成类程序的用户进入其界面。与其公开类本身,不如公开其接口,并仅将您希望公开的方法放在那里:

interface IBed {
    string Kind {get; set;}
    int Size {get; set;}
    bool HasBlankets {get; set;}
}
interface IHotelRoom {
    int RoomNumber {get; set;}
    IBed Bed {get;}
}
partial class HotelRoom : BaseModel, IHotelRoom {
    private class Bed : IBed {
        private HotelRoom room;
        internal Bed(HotelRoom room) {this.room = room;}
        public string Kind {
            get { return room.BedKind; }
            set { room.BedKind = value; }
        }
        ...
    }
    public IBed Bed {get;} = new Bed(this);
}

只要用户获得IHotelRom 对象,而不是HotelRoom,他们就无法访问HotelRoom 的公共属性,而无需显式强制转换。

【讨论】:

  • Nitpick:我认为您需要将嵌套类公开 :-)
  • @ChrisShain 不,因为它只公开为IBed
  • 是的,我的错,错过了上面的界面
  • 谢谢。无论如何,当将 HotelRoom 用作 IHotelRoom 时,我不太确定如何访问 BaseModel 的所有公共方法和属性以及 HotelRoom 的其他公共内容。此外,此解决方案将打破当前直接使用自动生成的类并在自定义分部类中添加任何其他所需的标准。这种方法在项目中很普遍,我认为改变它是不可能的(除非找到一个很好的理由)。
【解决方案2】:

一种方法可能是使自动生成的属性显式实现一个接口,该接口只公开给需要这些属性的代码。例如:

interface IPersistableHotelRoom { 
    int BedSize {get; set;}
}

public class HotelRoom : IPersistableHotelRoom {
    int IPersistableHotelRoom.BedSize { get; set; }

    public class Bed {
        private HotelRoom room; // set this in the nested class constructor, not shown
        public int Size { get { return room.BedSize; } }
    }

    public Bed Bed {get;}

    public HotelRoom() {
        this.Bed = new Bed(this);
    }
}

在上面的代码(未经测试,但应该可以工作)中,无权访问IPersistableHotelRoom 的代码永远不会看到那里定义的属性。 确实可以访问它的代码可以通过转换为IPersistableHotelRoom来访问这些属性:

var foo = ((IPersistableHotelRoom)hotelRoom).BedSize;

【讨论】:

  • 恐怕我无法控制自动生成的类。另外,我认为您的解决方案有点打破了使代码尽可能可读和可维护的最初目的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-26
  • 2020-07-01
相关资源
最近更新 更多