我有几个成员名为'Id'的课程。最初我想将这些存储为整数,但我想要一些保护层,以确保我不会意外地为一个人分配房间ID等。
一个解决方案是typedef(使用RoomId = System.Int32;)然后我需要使用这些代码在所有文件中。我希望例如从int32派生的RoomId类,但我无法弄清楚如何设置它以允许显式转换(用于初始化)
或者我应该以其他方式这样做?
答案 0 :(得分:32)
您无法从Int32
派生,但您可以指定隐式转化,这可能会为您提供所需的行为:
public struct RoomId
{
private int _Value;
public static implicit operator RoomId(int value)
{
return new RoomId { _Value = value };
}
public static implicit operator int(RoomId value)
{
return value._Value;
}
}
// ...
RoomId id = 42;
Console.WriteLine(id == 41); // False
Console.WriteLine(id == 42); // True
Console.WriteLine(id < 42); // False
Console.WriteLine(id > 41); // True
Console.WriteLine(id * 2); // 84
答案 1 :(得分:9)
public static explicit operator RoomId(int value) {
return new RoomId { Id = value };
}
然后你可以这样做:
RoomId variable = (RoomId)10;
无法从Int32
或C#中的任何其他值类型派生类。
答案 2 :(得分:7)
如果我理解正确,你真正需要的唯一操作就是平等比较。您可以创建一个RoomId类(或结构,适合您)
class RoomId
{
private int Value {get; set;}
public RoomId(int value)
{
this.Value = value;
}
public bool Equals(RoomId other)
{
return this.Value == other.Value;
}
}
RoomId room1 = new RoomId(1);
RoomId room2 = new RoomId(2);
// To compare for equality
bool isItTheSameRoom = room1.Equals(room2);
// Or if you have overloaded the equality operator (==)
bool isItTheSameRoom = room1 == room2;
如果需要,可以实现IEquatable,重载相等和不等运算符。如果需要持久性,可以实现ISerializable接口,以确保整数值仅在实际需要时“转义”类。
答案 3 :(得分:2)
您不能在.NET中继承值类型(结构,包括Int32)。
最接近的选择是创建一个只包含Int32的结构。这将需要相同的空间,但可能仅限于您的确切结构。然后,您可以在以后更改结构,以包含其他信息(如果需要)。 (但请注意,这可能会导致API更改。)
答案 4 :(得分:1)
我的偏好是使用简单的T4模板即时生成自定义类型。这是我最近在个人项目中使用的一个例子。在第10行,是生成的类型列表。这些东西过去都是int
,但现在它们都是强类型的。
这也通过避免通常的“原始痴迷”反模式,使你的代码转向使用更具功能性的范例。
我正在使用的模板。随意更新/修改(如果你添加任何有用的东西,让其他人知道。)
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
// List of types to generate:
var createTypeList = new[] { "XDim", "YDim", "YDelta", "DelayValue", "HValue", "Score", "TplIndexValue" };
#>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Contracts;
// ReSharper disable CheckNamespace
<#
for(int i = 0; i < createTypeList.Length; i++)
{
var typeName = createTypeList[i];
#>
[ImmutableObject(true)]
public struct <#=typeName#> : IComparable<<#=typeName#>>
{
public <#=typeName#>(int value) { Value = value; }
[Pure] public int Value { get; }
[Pure] public bool Equals(<#=typeName#> other) => Value == other.Value;
[Pure]
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (Equals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((<#=typeName#>)obj);
}
[Pure]
public override int GetHashCode()
{
unchecked
{
return (base.GetHashCode() * 397) ^ Value;
}
}
[Pure] public static bool operator ==(<#=typeName#> left, <#=typeName#> right) => Equals(left, right);
[Pure] public static bool operator !=(<#=typeName#> left, <#=typeName#> right) => !Equals(left, right);
[Pure] public int CompareTo(<#=typeName#> other) => Equals(this, other) ? 0 : Value.CompareTo(other.Value);
[Pure] public static bool operator <(<#=typeName#> left, <#=typeName#> right) => Comparer<<#=typeName#>>.Default.Compare(left, right) < 0;
[Pure] public static bool operator >(<#=typeName#> left, <#=typeName#> right) => Comparer<<#=typeName#>>.Default.Compare(left, right) > 0;
[Pure] public static bool operator <=(<#=typeName#> left, <#=typeName#> right) => Comparer<<#=typeName#>>.Default.Compare(left, right) <= 0;
[Pure] public static bool operator >=(<#=typeName#> left, <#=typeName#> right) => Comparer<<#=typeName#>>.Default.Compare(left, right) >= 0;
[Pure] public override string ToString() => $"{nameof(Value)}: {Value}";
}
<#
}
#>