c# - 持续引用的最佳方法或替代方案是什么?

标签 c# const-correctness compile-time-constant

就本问题而言,“常量引用”是对对象的引用,您无法从中调用修改该对象或修改其属性的方法。

我想要这样的东西:

Const<User> user = provider.GetUser(); // Gets a constant reference to an "User" object
var name = user.GetName(); // Ok. Doesn't modify the object
user.SetName("New value"); // <- Error. Shouldn't be able to modify the object

理想情况下,我会用自定义属性(例如[Constant])标记不修改实例的类的每个方法,并且只能从常量引用调用这些方法。如果可能的话,在编译期间调用其他方法将导致错误。

这个想法是我可以返回一个只读引用并确保它不会被客户端修改。

最佳答案

您所指的技术称为 " const -correctness"不幸的是,这是 C++ 和 Swift 的语言功能,但不是 C# 的语言功能 - 但是您可以通过使用自定义属性来实现某些功能,因为这样您可以通过 Roslyn 扩展来强制执行它 - 但这是一个兔子洞。

或者,有一个使用接口(interface)的更简单的解决方案:因为 C#(我认为 CLR 也是如此)不支持 const 正确性(我们拥有的最接近的是 readonly 字段修饰符).NET 基类库设计者向常见的可变类型添加了“只读接口(interface)”,以允许对象(无论可变或不可变)通过仅公开不可变操作的接口(interface)来公开其功能。一些示例包括IReadOnlyList<T> , IReadOnlyCollection<T> , IReadOnlyDictionary<T> - 虽然这些都是可枚举类型,但该技术也适用于单一对象。

这种设计的优点是可以在任何支持接口(interface)但不支持常量正确性的语言中工作。

  1. 对于项目中需要公开数据而不存在更改风险的每种类型( classstruct 等)或任何不可变操作,然后创建一个不可变接口(interface)。
  2. 修改您的使用代码以使用这些接口(interface)而不是具体类型。

像这样:

假设我们有一个可变类 User和消费服务:

public class User
{
    public String UserName     { get; set; }

    public Byte[] PasswordHash { get; set; }
    public Byte[] PasswordSalt { get; set; }

    public Boolean ValidatePassword(String inputPassword)
    {
        Hash[] inputHash = Crypto.GetHash( inputPassword, this.PasswordSalt );
        return Crypto.CompareHashes( this.PasswordHash, inputHash );
    }

    public void ResetSalt()
    {
        this.PasswordSalt = Crypto.GetRandomBytes( 16 );
    }
}

public static void DoReadOnlyStuffWithUser( User user )
{
    ...
}

public static void WriteStuffToUser( User user )
{
    ...
}

然后制作一个不可变的接口(interface):

public interface IReadOnlyUser
{
    // Note that the interfaces' properties lack setters.
    String              UserName     { get; }
    IReadOnlyList<Byte> PasswordHash { get; }
    IReadOnlyList<Byte> PasswordSalt { get; }

    // ValidatePassword does not mutate state so it's exposed
    Boolean ValidatePassword(String inputPassword);

    // But ResetSalt is not exposed because it mutates instance state
}

然后修改你的User类和消费者:

public class User : IReadOnlyUser
{
    // (same as before, except need to expose IReadOnlyList<Byte> versions of array properties:
    IReadOnlyList<Byte> IReadOnlyUser.PasswordHash => this.PasswordHash;
    IReadOnlyList<Byte> IReadOnlyUser.PasswordSalt => this.PasswordSalt;
}

public static void DoReadOnlyStuffWithUser( IReadOnlyUser user )
{
    ...
}

// This method still uses `User` instead of `IReadOnlyUser` because it mutates the instance.
public static void WriteStuffToUser( User user )
{
    ...
}

关于c# - 持续引用的最佳方法或替代方案是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53463876/

相关文章:

c++ - 常量的编译时检查

c# - 具有径向渐变的 WPF 径向进度条

c# - 如何将类对象转换为字符串?

c++ - 将 const 添加到指针类型

const array[][] 作为 C 中的形式参数 - 不匹配

c++ - 通过 const& 和通过 & 将对象传递给同一个函数

c++ - MSVC 接受用 nullptr 初始化的指向 int 的常量指针作为常量表达式

java - 开关 : Why can't this be done? 中的静态最终 Int

c# - 我的逻辑在这里需要一点帮助。我怎样才能让图片在点击时选择更改图像?

c# - C# 中漂亮的键名(窗体)