2009-05-11 2 views
13

'Id'라는 멤버가있는 클래스가 여러 개 있습니다. 원래 int로 저장하고 싶었지만 실수로 방 ID를 사람에게 할당하지 않도록 일부 보호 계층을 원합니다.int32에서 파생되는 C#

하나의 솔루션은 RoomId = System을 사용하여 typedef가됩니다. Int32;)하지만이 코드를 사용하는 모든 파일에서이 코드 줄이 필요합니다. 나는 예를 들면. int32에서 파생 된 RoomId 클래스,하지만 내가 (초기화)에 대한 명시적인 변환을 허용하도록 설정하는 방법을 알아낼 수 없다

또는 다른 방법으로해야합니까?

답변

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 인터페이스를 구현하여 정수 값이 실제로 필요한 경우 클래스를 "이스케이프"합니다.

+0

개인 값에 유형이 없습니다? 그게 맞습니까? – bendewey

+0

@bendewey : 오타였습니다. 그것을 지적 해 주셔서 감사합니다. –

+0

우수, 감사합니다! 에 추가 답변이 있습니다. 이후 다른 ID를 몇 가지 필요, 내가이 일을 마스터 ID 클래스를 가지고 있어야하고, 그런 다음 그냥 하위를 파생시키는 것 같습니다.그러나 이것은 내가 생각한 것처럼 작동하지 않는 것 같습니다. 는 ID에 위의 이름을 변경하고 공용 클래스 ParticipantID를 작성 : – second

9
public static explicit operator RoomId(int value) { 
    return new RoomId { Id = value }; 
} 

당신은 할 수 :

RoomId variable = (RoomId)10; 

그것은 Int32 또는 C#에서 다른 값 유형에서 클래스를 파생 할 수 없습니다.

+0

그렇다면 myRoom.Id.id를 사용하여 액세스해야합니까? int (예 : myRoom.Id)처럼 작동하도록하고 싶습니다. (값을 비교하는 등) – second

+0

아니요, myRoom.Id가 작동합니다. 다른 답변에서 언급 한 동등 비교자를 구현할 수도 있습니다. –

2

.NET에서 값 유형 (구조체, Int32 포함)을 상속받을 수 없습니다.

가장 가까운 옵션은 Int32 만 포함 된 구조체를 만드는 것입니다. 이것은 같은 공간이 필요하지만 정확한 구조체로 제한 될 수 있습니다. 그런 다음 필요할 경우 다른 정보를 포함하도록 구조체를 나중에 변경할 수 있습니다. 그러나 이것이 API 변경을 깨뜨릴 수 있음을 염두에 두십시오.

26

당신은 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 
+0

우수 솔루션 –

+0

필요한 모든 메소드와 연산자를 오버라이드하는 것보다 확실히 간결합니다. – Shocked

+0

그레이트 솔루션. 나는 또한'IEquatable' 구현을 추가 할 것입니다. – sdgfsdh

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}"; 
    } 
<# 
    } 
#> 
+0

나는 대답하기 전에 실제로 T4 템플릿을 들어 본 적이 없었다. 확실히 나는 그것을 우연히 만났기 때문에 기쁘다. 컴파일 오류를 수정하기 위해 작은 편집을했습니다. 내가 말할 수있는 한 그것이 유효 함에도 불구하고 생성자가 설정된 방식을 좋아하지 않는 것처럼 보였으므로 더 일반적인 구문을 사용하도록 만들었습니다. –

+0

Eagle-Eye, 감사합니다. 코드 변경에 대해서는 아무런 문제가 없지만 솔직히 말해서 나는 당신의 야당이 정확히 무엇인지 확신 할 수 없습니다. C# 6 구문의 경우 클래스의 맨 아래에있는 나머지 메서드뿐만 아니라 Equals() 메서드도 변경해야합니다. 특별히 다른 구문을 사용하기 위해 생성자를 선택하는 이유는 무엇입니까? 나는 뭔가를 놓친 것 같은 기분이야. – zumalifeguard

+0

내가 말했듯이 컴파일러는 C# 6 구문을 사용하여 생성자와 오류를 던지고있었습니다. Intellisense는''public XDim (int value) => Value = value;''XDim.XDim (int) '은 abstract, extern 또는 partial으로 표시되지 않기 때문에 본문을 선언해야합니다. '이름'값 '은 현재 컨텍스트에 존재하지 않습니다.'등이 있습니다. 이상하게도 생성자에만 문제가 없습니다. VS2015 및 .NET Framework 4.6.1 등이 있습니다. –

관련 문제