简体   繁体   中英

How the get derived class type from base class

I'm trying to refactor a method which I use in a lot of clases. It's simpler to explain it by an example.

I have this class:

    public class TipoPuntoClaveConst
    {
        public const int Insercion = 1;
        public const int DetectorDePaso = 2;
        public const int Sincronizador = 3;
        public const int Extraccion = 4;

        public static string GetDescripcion(int IdxTipo)
        {
            var property = typeof(TipoPuntoClaveConst)
                .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
                .Where(fi => fi.IsLiteral && !fi.IsInitOnly && (int)fi.GetRawConstantValue() == IdxTipo)
                .FirstOrDefault();

            if (property == null) return string.Empty;
            var name = property.Name;
            return ResourceHelper.GetTraduccion(ResourceHelper.FICHERO.General, name);
        }
    }

In the project, I also have a ResourceFile for localization. The GetDescription method, returns the localized text using the correct property name given a value. You can see an example of use:

<html>
    <body>
        <select id="cbTipo">
            <option value="@TipoPuntoClaveConst.Insercion">@TipoPuntoClaveConst.GetDescripcion(TipoPuntoClaveConst.Insercion)</option>
            ...
        </select>
    </body>
</html>

The problem is, that I have to copy-paste that method in all of my const classes. I'm trying to implement this method in a base class, something like:

public class TipoPuntoClaveConst : ConstMaster {...}

public class ConstMaster {
    public static string GetDescripcion(int IdxTipo)
    {
        var property = typeof(TipoPuntoClaveConst)
            .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
            .Where(fi => fi.IsLiteral && !fi.IsInitOnly && (int)fi.GetRawConstantValue() == IdxTipo)
            .FirstOrDefault();

        if (property == null) return string.Empty;
        var name = property.Name;
        return ResourceHelper.GetTraduccion(ResourceHelper.FICHERO.General, name);
    }
}

But I cannot figure out, how to replace var property = typeof(TipoPuntoClaveConst) , for something more general, like var property = typeof(¿this?)

When you call the GetDescription method it will be either the base class object itself or some derived class object. But in base you don't know which dervied class it is. You will need to use GetType method to get it's actual type on run-time as @bradbury9 mentioned in the comments like:

public string GetDescripcion(int IdxTipot)
{
    var property = this.GetType()
            .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
            .Where(fi => fi.IsLiteral && !fi.IsInitOnly && (int)fi.GetRawConstantValue() == IdxTipo)
            .FirstOrDefault();

   if (property == null) return string.Empty;
    var name = property.Name;
    return ResourceHelper.GetTraduccion(ResourceHelper.FICHERO.General, name);
}

It's better to keep it as instance method, if you really need it as static then you will need to take the object as parameter input:

public static string GetDescripcion(int IdxTipo,TipoPuntoClaveConst objec)
{
    var property = object.GetType()
            .GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
            .Where(fi => fi.IsLiteral && !fi.IsInitOnly && (int)fi.GetRawConstantValue() == IdxTipo)
            .FirstOrDefault();

   if (property == null) return string.Empty;
    var name = property.Name;
    return ResourceHelper.GetTraduccion(ResourceHelper.FICHERO.General, name);
}

As long as your problem is with types and inheritance, I am explaining you the alternatives you do have but avoiding the reflection part.

  1. Non static method getting the type using this.GetType()
  2. Static method, providing an instance of the class as an function parameter.
  3. Static generic method, not providing and instance.

I would go the non-static because of simplicity, but it depends on the usage you want to give it. From your comments on your question, you could take advantage of generics.

namespace InheritanceTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"Base: {new BaseClass().CheckType()}");
            Console.WriteLine($"Child: {new ChildClass().CheckType()}");
            Console.WriteLine($"Static in base with child argument: {BaseClass.CheckType(new ChildClass())}");
            Console.WriteLine($"Static generic in base:{BaseClass.CheckType<ChildClass>()}");
            Console.ReadLine();
        }
    }

    public class BaseClass
    {
        public string CheckType()
        {
            return this.GetType().ToString();
        }

        public static string CheckType(BaseClass instance)
        {
            return instance.GetType().ToString();
        }

        public static string CheckType<T>() where T: BaseClass
        {
            return typeof(T).ToString();
        }
    }

    public class ChildClass : BaseClass
    {
    }
}

The output is the following one

Base: InheritanceTest.BaseClass
Child: InheritanceTest.ChildClass
Static in base with child argument: InheritanceTest.ChildClass
Static generic in base: InheritanceTest.ChildClass

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM