0

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"

thalacker
  • 2,389
  • 3
  • 23
  • 44
  • Do you mean `MyModelClass.MyTranslatingType myType = MyModelClass.MyTranslatingType.ThirdType;`? Your code intent is not obvious. – DavidG Mar 13 '20 at 15:30
  • @DavidG I have updated it to better explain what I want `myType` to equal (its at the bottom) – thalacker Mar 13 '20 at 15:40

4 Answers4

1

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}");
    }
}
DavidG
  • 113,891
  • 12
  • 217
  • 223
  • I agree that is cleaner and I think it's close, but the properties need to exist somewhere (I think they would fit better in the `MyTranslatingType` vs `MyModelClass`). Thoughts? – thalacker Mar 13 '20 at 15:53
  • Wh do the properties need to exist anywhere? – DavidG Mar 13 '20 at 16:07
  • Because of the `nameof`. If you copy the class you have above into an empty file, it complain that the `FirstType` and `SecondType` do not exist in the context. – thalacker Mar 13 '20 at 16:26
  • Then make them private constants instead. See my update. – DavidG Mar 13 '20 at 16:27
1

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.
Mike-314
  • 351
  • 2
  • 6
  • Not sure you need it to be an implicit operator, but I do like the switch expressions, though you should probably state that's only in C# 8, and therefore .NET Core 3. – DavidG Mar 13 '20 at 15:50
0

typeof(MyModelClass.MyTranslatingType).GetProperty("ThirdType") return a PropertyInfo.

To get the value :

var myType = (MyModelClass.MyTranslatingType)typeof(MyModelClass.MyTranslatingType).GetProperty("ThirdType").GetGetMethod().Invoke(null, null);
vernou
  • 6,818
  • 5
  • 30
  • 58
0

using System; using System.Reflection;

namespace ConsoleApp1 {

// Outer class 
public class Outer_class
{

    // Method of outer class 
    public void method1()
    {
        Console.WriteLine("Outer class method");
    }

    // Inner class 
    public class Inner_class
    {

        private Inner_class(string value) { Value = value; }

        public string Value { get; set; }

        public static Inner_class FirstType => new Inner_class(nameof(FirstType));


    }
}

class Program
{
    private const string Name = "FirstType";

    static void Main(string[] args)
    {
        PropertyInfo obj = typeof(Outer_class.Inner_class).GetProperty(Name);

        Console.WriteLine(obj.Name);

        Console.WriteLine(obj.PropertyType);


    }
}