You can try DRY here :)
Define class like this (UPDATED to include ASP.NET support):
[TypeConverter(typeof(IdTypeConverter))]
[JsonConverter(typeof(IdJsonConverter))]
public struct Id<T>
{
public static explicit operator Id<T>(int value) => new Id<T>(value);
public static implicit operator int(Id<T> id) => id.Value;
public Id(int value)
: this()
{
Value = value;
}
int Value { get; }
public override int GetHashCode() => Value.GetHashCode();
public override bool Equals(object obj) =>
obj is Id<T> &&
((Id<T>)obj).Value == Value;
public static bool operator ==(Id<T> left, Id<T> right) =>
left.Value == right.Value;
public static bool operator !=(Id<T> left, Id<T> right) =>
left.Value != right.Value;
}
class IdJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return
objectType.IsConstructedGenericType &&
objectType.GetGenericTypeDefinition() == typeof(Id<>);
}
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
return Activator.CreateInstance(
objectType,
reader.ReadAsInt32());
}
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
writer.WriteValue((int)(dynamic)value);
}
}
class IdTypeConverter : TypeConverter
{
public IdTypeConverter(Type type)
{
Type = type;
}
Type Type { get; }
public override bool CanConvertFrom(
ITypeDescriptorContext context, Type sourceType)
{
return
sourceType == typeof(string) ||
base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(
ITypeDescriptorContext context,
CultureInfo culture, object value)
{
if (value is string)
return Activator.CreateInstance(
Type,
int.Parse(value as string));
return base.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(
ITypeDescriptorContext context,
Type destinationType)
{
return
destinationType == typeof(string) ||
base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(
ITypeDescriptorContext context,
CultureInfo culture,
object value,
Type destinationType)
{
if (destinationType == typeof(string))
return $"{(int)(dynamic)value}";
return base.ConvertTo(context, culture, value, destinationType);
}
}
Let's imagine you have Entity Framework Entity Type User
:
class User
{
public int Id { get; set; }
public string Name { get; set; }
}
Then:
IUserReader reader = new UserReader();
User dirkBoer = reader.Read(Users.DirkBoer);
Where:
class Users
{
public static readonly Id<User> DirkBoer = (Id<User>)22;
public static readonly Id<User> Jamal = (Id<User>)23;
}
class UserReader : IUserReader
{
public User Read(Id<User> id) =>
Users().First(u => u.Id == id);
IQueryable<User> Users() =>
new EfContext()
.Users
.Include(u => u.Certificates);
}