How to cast string to class property

c# casting entity-framework-core

Question

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"

1
0
3/13/2020 3:39:56 PM

Accepted Answer

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)
    };
}
  • Note, switch statement is C# 8. you can update to use traditional switch syntax.
1
3/13/2020 3:50:27 PM

Popular Answer

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 consts 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}");
    }
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow