就本问题而言,“常量引用”是对对象的引用,您无法从中调用修改该对象或修改其属性的方法。
我想要这样的东西:
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)但不支持常量正确性的语言中工作。
- 对于项目中需要公开数据而不存在更改风险的每种类型(
class
、struct
等)或任何不可变操作,然后创建一个不可变接口(interface)。 - 修改您的使用代码以使用这些接口(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/