I have a model for my database (using efcore to translate between model and database) that contains a string that can be three values.
In order to better control the string values going into the db, I created an enum of sorts (which you can't do in C# so I followed this model).
public class MyModelClass
{
public int Id { get; protected set; }
public string MyString { get; protected set; }
public MyModelClass(int id, MyTranslatingType type)
{
Id = id;
MyString = type.Value;
}
public class MyTranslatingType
{
private MyTranslatingType(string value) { Value = value; }
public string Value { get; set; }
public static MyTranslatingType FirstType
=> new MyTranslatingType(nameof(FirstType));
public static MyTranslatingType SecondType
=> new MyTranslatingType (nameof(SecondType));
public static MyTranslatingType ThirdType
=> new MyTranslatingType (nameof(ThirdType));
}
}
However, when I try to grab values from the database, I can't just cast them, or use typeof()
because they are properties and not a traditional enum/type.
I have tried
// error saying it can't convert [PropertyInfo][2] to MyModelClass.MyTranslatingType
MyModelClass.MyTranslatingType myType = typeof(MyModelClass.MyTranslatingType).GetProperty("ThirdType");
// error saying it can't convert string to MyModelClass.MyTranslatingType
MyModelClass.MyTranslatingType myType = (MyModelClass.MyTranslatingType)"ThirdType";
How can I cast a string of "ThirdType"
to a property like MyModelClass.MyTranslatingType.ThirdType
?
In other words, I want myType
to equal MyModelClass.MyTranslatingType.ThirdType
for
var myType = (MyModelClass.MyTranslatingType)"ThirdType"
If you want to cast one type to another: string to MyTranslatingType you need an implicit or explicit cast operator:
public static implicit operator string(MyTranslatingType tp) => tp?.Value;
public static implicit operator MyTranslatingType(string value)
{
return value switch
{
nameof(FirstType) => FirstType,
nameof(SecondType) => SecondType,
nameof(ThirdType) => ThirdType,
_ => new MyTranslatingType(value)
};
}
I think you are looking for a factory pattern of sorts. You can do it something like this:
public class MyTranslatingType
{
// A dictionary of methods to get the relevant type
private static Dictionary<string, Func<MyTranslatingType>> _typeFactory =
new Dictionary<string, System.Func<MyModelClass.MyTranslatingType>>
{
{ nameof(FirstType), () => new MyTranslatingType(nameof(FirstType)) },
{ nameof(SecondType), () => new MyTranslatingType(nameof(SecondType)) },
{ nameof(ThirdType), () => new MyTranslatingType(nameof(ThirdType)) },
};
// Method to get the type required
public static MyTranslatingType GetMyTranslatingType(string type)
{
if (_typeFactory.TryGetValue(type, out var getType))
{
return getType();
}
throw new ArgumentOutOfRangeException(nameof(type), $"Cannot get type for {type}");
}
}
And you use it like this:
var myType = MyModelClass.MyTranslatingType.GetMyTranslatingType("FirstType");
This method is cleaner than yours as we now no longer have a bunch of public static methods to get types.
Here is a full version using const
s instead of properties:
public class MyTranslatingType
{
private const string FirstType = "FirstType";
private const string SecondType = "SecondType";
private const string ThirdType = "ThirdType";
private MyTranslatingType(string value) { Value = value; }
public string Value { get; set; }
// A dictionary of methods to get the relevant type
private static Dictionary<string, Func<MyTranslatingType>> _typeFactory =
new Dictionary<string, System.Func<MyModelClass.MyTranslatingType>>
{
{ FirstType, () => new MyTranslatingType(FirstType) },
{ SecondType, () => new MyTranslatingType(SecondType) },
{ ThirdType, () => new MyTranslatingType(ThirdType) },
};
// Method to get the type required
public static MyTranslatingType GetMyTranslatingType(string type)
{
if (_typeFactory.TryGetValue(type, out var getType))
{
return getType();
}
throw new ArgumentOutOfRangeException(nameof(type), $"Cannot get type for {type}");
}
}