현재 또는 미래에 유선으로 연결 될까요 (직렬화 / 직렬화)? who-knows-how-large 전체 오브젝트보다 단일 ID 유형을 선호하십시오.
엔터티에 대한 ID의 유형 안전성을 찾고 있다면 코드 솔루션도 있습니다. 예가 필요하면 알려주십시오.
편집 : ID의 유형 안전 확장 :
그래서, 당신의 방법을 보자 :
public Foo GetItem(int id) {}
우리는 희망 정수 것을 id
전달있어 A에 대한 것입니다 Foo
객체입니다. 누군가 그것을 잘못 사용하여 Bar
객체의 정수 ID를 전달하거나 심지어 손으로 입력 할 수도 812341
있습니다. 에 안전한 유형이 아닙니다 Foo
. 둘째, 객체 Foo
버전 전달을 사용해도 누군가 수정할 수 Foo
있는 ID 필드가 있다고 확신 int
합니다. 마지막으로 반환 유형 만 다르므로 클래스에 메서드 오버로드가 있으면 메서드 오버로드를 사용할 수 없습니다. 이 메소드를 C #에서 타입 안전하게 보이도록 다시 작성해 보겠습니다.
public Foo GetItem(IntId<Foo> id) {}
그래서 나는 IntId
일반적인 부분을 가진 클래스를 소개 했습니다. 이 특별한 경우 에만 int
관련 이있는 것을 원합니다 Foo
. 나는 단지 나체를 통과 int
하거나 IntId<Bar>
실수로 그것을 할당 할 수 없습니다 . 아래는 이러한 유형 안전 식별자를 작성한 방법입니다. 실제 기본의 조작이 있음을 걸릴 노트를 수행 int
입니다 만 데이터 액세스 계층에서. 위의 내용은 강력한 유형 만보고 내부 int
ID에 대한 (직접) 액세스 권한이 없습니다 . 이유가 없어야합니다.
IModelId.cs 인터페이스 :
namespace GenericIdentifiers
{
using System.Runtime.Serialization;
using System.ServiceModel;
/// <summary>
/// Defines an interface for an object's unique key in order to abstract out the underlying key
/// generation/maintenance mechanism.
/// </summary>
/// <typeparam name="T">The type the key is representing.</typeparam>
[ServiceContract]
public interface IModelId<T> where T : class
{
/// <summary>
/// Gets a string representation of the domain the model originated from.
/// </summary>
/// <value>The origin.</value>
[DataMember]
string Origin
{
[OperationContract]get;
}
/// <summary>
/// The model instance identifier for the model object that this <see cref="IModelId{T}"/> refers to.
/// Typically, this is a database key, file name, or some other unique identifier.
/// <typeparam name="TKeyDataType">The expected data type of the identifier.</typeparam>
/// </summary>
/// <typeparam name="TKeyDataType">The expected data type of the identifier.</typeparam>
/// <returns>The unique key as the data type specified.</returns>
[OperationContract]
TKeyDataType GetKey<TKeyDataType>();
/// <summary>
/// Performs an equality check on the two model identifiers and returns <c>true</c> if they are equal; otherwise
/// <c>false</c> is returned. All implementations must also override the equal operator.
/// </summary>
/// <param name="obj">The identifier to compare against.</param>
/// <returns><c>true</c> if the identifiers are equal; otherwise <c>false</c> is returned.</returns>
[OperationContract]
bool Equals(IModelId<T> obj);
}
}
ModelIdBase.cs 기본 클래스 :
namespace GenericIdentifiers
{
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
/// <summary>
/// Represents an object's unique key in order to abstract out the underlying key generation/maintenance mechanism.
/// </summary>
/// <typeparam name="T">The type the key is representing.</typeparam>
[DataContract(IsReference = true)]
[KnownType("GetKnownTypes")]
public abstract class ModelIdBase<T> : IModelId<T> where T : class
{
/// <summary>
/// Gets a string representation of the domain the model originated from.
/// </summary>
[DataMember]
public string Origin
{
get;
internal set;
}
/// <summary>
/// The model instance identifier for the model object that this <see cref="ModelIdBase{T}"/> refers to.
/// Typically, this is a database key, file name, or some other unique identifier.
/// </summary>
/// <typeparam name="TKeyDataType">The expected data type of the identifier.</typeparam>
/// <returns>The unique key as the data type specified.</returns>
public abstract TKeyDataType GetKey<TKeyDataType>();
/// <summary>
/// Performs an equality check on the two model identifiers and returns <c>true</c> if they are equal;
/// otherwise <c>false</c> is returned. All implementations must also override the equal operator.
/// </summary>
/// <param name="obj">The identifier to compare against.</param>
/// <returns>
/// <c>true</c> if the identifiers are equal; otherwise <c>false</c> is returned.
/// </returns>
public abstract bool Equals(IModelId<T> obj);
protected static IEnumerable<Type> GetKnownTypes()
{
return new[] { typeof(IntId<T>), typeof(GuidId<T>) };
}
}
}
IntId.cs :
namespace GenericIdentifiers
{
// System namespaces
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
/// <summary>
/// Represents an abstraction of the database key for a Model Identifier.
/// </summary>
/// <typeparam name="T">The expected owner data type for this identifier.</typeparam>
[DebuggerDisplay("Origin={Origin}, Integer Identifier={Id}")]
[DataContract(IsReference = true)]
public sealed class IntId<T> : ModelIdBase<T> where T : class
{
/// <summary>
/// Gets or sets the unique ID.
/// </summary>
/// <value>The unique ID.</value>
[DataMember]
internal int Id
{
get;
set;
}
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="intIdentifier1">The first Model Identifier to compare.</param>
/// <param name="intIdentifier2">The second Model Identifier to compare.</param>
/// <returns>
/// <c>true</c> if the instances are equal; otherwise <c>false</c> is returned.
/// </returns>
public static bool operator ==(IntId<T> intIdentifier1, IntId<T> intIdentifier2)
{
return object.Equals(intIdentifier1, intIdentifier2);
}
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="intIdentifier1">The first Model Identifier to compare.</param>
/// <param name="intIdentifier2">The second Model Identifier to compare.</param>
/// <returns>
/// <c>true</c> if the instances are equal; otherwise <c>false</c> is returned.
/// </returns>
public static bool operator !=(IntId<T> intIdentifier1, IntId<T> intIdentifier2)
{
return !object.Equals(intIdentifier1, intIdentifier2);
}
/// <summary>
/// Performs an implicit conversion from <see cref="IntId{T}"/> to <see cref="System.Int32"/>.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator int(IntId<T> id)
{
return id == null ? int.MinValue : id.GetKey<int>();
}
/// <summary>
/// Performs an implicit conversion from <see cref="System.Int32"/> to <see cref="IntId{T}"/>.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator IntId<T>(int id)
{
return new IntId<T> { Id = id };
}
/// <summary>
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current
/// <see cref="T:System.Object"/>.
/// </summary>
/// <param name="obj">The <see cref="T:System.Object"/> to compare with the current
/// <see cref="T:System.Object"/>.</param>
/// <returns>true if the specified <see cref="T:System.Object"/> is equal to the current
/// <see cref="T:System.Object"/>; otherwise, false.</returns>
/// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
public override bool Equals(object obj)
{
return this.Equals(obj as IModelId<T>);
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = (23 * hash) + (this.Origin == null ? 0 : this.Origin.GetHashCode());
return (31 * hash) + this.GetKey<int>().GetHashCode();
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return this.Origin + ":" + this.GetKey<int>().ToString(CultureInfo.InvariantCulture);
}
/// <summary>
/// Performs an equality check on the two model identifiers and returns <c>true</c> if they are equal;
/// otherwise <c>false</c> is returned. All implementations must also override the equal operator.
/// </summary>
/// <param name="obj">The identifier to compare against.</param>
/// <returns>
/// <c>true</c> if the identifiers are equal; otherwise <c>false</c> is returned.
/// </returns>
public override bool Equals(IModelId<T> obj)
{
if (obj == null)
{
return false;
}
return (obj.Origin == this.Origin) && (obj.GetKey<int>() == this.GetKey<int>());
}
/// <summary>
/// The model instance identifier for the model object that this <see cref="ModelIdBase{T}"/> refers to.
/// Typically, this is a database key, file name, or some other unique identifier.
/// </summary>
/// <typeparam name="TKeyDataType">The expected data type of the identifier.</typeparam>
/// <returns>The unique key as the data type specified.</returns>
public override TKeyDataType GetKey<TKeyDataType>()
{
return (TKeyDataType)Convert.ChangeType(this.Id, typeof(TKeyDataType), CultureInfo.InvariantCulture);
}
/// <summary>
/// Generates an object from its string representation.
/// </summary>
/// <param name="value">The value of the model's type.</param>
/// <returns>A new instance of this class as it's interface containing the value from the string.</returns>
internal static ModelIdBase<T> FromString(string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
int id;
var originAndId = value.Split(new[] { ":" }, StringSplitOptions.None);
if (originAndId.Length != 2)
{
throw new ArgumentOutOfRangeException("value", "value must be in the format of Origin:Identifier");
}
return int.TryParse(originAndId[1], NumberStyles.None, CultureInfo.InvariantCulture, out id)
? new IntId<T> { Id = id, Origin = originAndId[0] }
: null;
}
}
}
그리고 코드베이스의 완전성을 위해 GUID 엔터티 인 GuidId.cs를 작성했습니다.
namespace GenericIdentifiers
{
// System namespaces
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
/// <summary>
/// Represents an abstraction of the database key for a Model Identifier.
/// </summary>
/// <typeparam name="T">The expected owner data type for this identifier.</typeparam>
[DebuggerDisplay("Origin={Origin}, GUID={Id}")]
[DataContract(IsReference = true)]
public sealed class GuidId<T> : ModelIdBase<T> where T : class
{
/// <summary>
/// Gets or sets the unique ID.
/// </summary>
/// <value>The unique ID.</value>
[DataMember]
internal Guid Id
{
get;
set;
}
/// <summary>
/// Implements the operator ==.
/// </summary>
/// <param name="guidIdentifier1">The first Model Identifier to compare.</param>
/// <param name="guidIdentifier2">The second Model Identifier to compare.</param>
/// <returns>
/// <c>true</c> if the instances are equal; otherwise <c>false</c> is returned.
/// </returns>
public static bool operator ==(GuidId<T> guidIdentifier1, GuidId<T> guidIdentifier2)
{
return object.Equals(guidIdentifier1, guidIdentifier2);
}
/// <summary>
/// Implements the operator !=.
/// </summary>
/// <param name="guidIdentifier1">The first Model Identifier to compare.</param>
/// <param name="guidIdentifier2">The second Model Identifier to compare.</param>
/// <returns>
/// <c>true</c> if the instances are equal; otherwise <c>false</c> is returned.
/// </returns>
public static bool operator !=(GuidId<T> guidIdentifier1, GuidId<T> guidIdentifier2)
{
return !object.Equals(guidIdentifier1, guidIdentifier2);
}
/// <summary>
/// Performs an implicit conversion from <see cref="GuidId{T}"/> to <see cref="System.Guid"/>.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator Guid(GuidId<T> id)
{
return id == null ? Guid.Empty : id.GetKey<Guid>();
}
/// <summary>
/// Performs an implicit conversion from <see cref="System.Guid"/> to <see cref="GuidId{T}"/>.
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator GuidId<T>(Guid id)
{
return new GuidId<T> { Id = id };
}
/// <summary>
/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current
/// <see cref="T:System.Object"/>.
/// </summary>
/// <param name="obj">The <see cref="T:System.Object"/> to compare with the current
/// <see cref="T:System.Object"/>.</param>
/// <returns>true if the specified <see cref="T:System.Object"/> is equal to the current
/// <see cref="T:System.Object"/>; otherwise, false.</returns>
/// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
public override bool Equals(object obj)
{
return this.Equals(obj as IModelId<T>);
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns>
/// A hash code for the current <see cref="T:System.Object"/>.
/// </returns>
public override int GetHashCode()
{
unchecked
{
var hash = 17;
hash = (23 * hash) + (this.Origin == null ? 0 : this.Origin.GetHashCode());
return (31 * hash) + this.GetKey<Guid>().GetHashCode();
}
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return this.Origin + ":" + this.GetKey<Guid>();
}
/// <summary>
/// Performs an equality check on the two model identifiers and returns <c>true</c> if they are equal;
/// otherwise <c>false</c> is returned. All implementations must also override the equal operator.
/// </summary>
/// <param name="obj">The identifier to compare against.</param>
/// <returns>
/// <c>true</c> if the identifiers are equal; otherwise <c>false</c> is returned.
/// </returns>
public override bool Equals(IModelId<T> obj)
{
if (obj == null)
{
return false;
}
return (obj.Origin == this.Origin) && (obj.GetKey<Guid>() == this.GetKey<Guid>());
}
/// <summary>
/// The model instance identifier for the model object that this <see cref="ModelIdBase{T}"/> refers to.
/// Typically, this is a database key, file name, or some other unique identifier.
/// </summary>
/// <typeparam name="TKeyDataType">The expected data type of the identifier.</typeparam>
/// <returns>The unique key as the data type specified.</returns>
public override TKeyDataType GetKey<TKeyDataType>()
{
return (TKeyDataType)Convert.ChangeType(this.Id, typeof(TKeyDataType), CultureInfo.InvariantCulture);
}
/// <summary>
/// Generates an object from its string representation.
/// </summary>
/// <param name="value">The value of the model's type.</param>
/// <returns>A new instance of this class as it's interface containing the value from the string.</returns>
internal static ModelIdBase<T> FromString(string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
Guid id;
var originAndId = value.Split(new[] { ":" }, StringSplitOptions.None);
if (originAndId.Length != 2)
{
throw new ArgumentOutOfRangeException("value", "value must be in the format of Origin:Identifier");
}
return Guid.TryParse(originAndId[1], out id) ? new GuidId<T> { Id = id, Origin = originAndId[0] } : null;
}
}
}