How to get the current type from a static method in an abstract class?

How can I get the current Type in a static method that is defined in an abstract class?

Note that since the method is defined in an abstract class, I cannot use typeof .

Why do I want to do this? Possible use of attributes. Consider the following example:

 [Identifier(1000)] public class Rock : Entity { } public abstract class Entity { public static ushort Identifier { get { // How do I get here the current type of the object? Type currentType = ...; // in a non-static method or property, I'd do: // Type currentType = this.GetType(); foreach (IdentifierAttribute attribute in currentType.GetCustomAttributes(true)) return attribute.Identifier; throw new EntityException("No identifier has specified for this type of entity."); } } } Rock rock = new Rock(); // should print 1000 Console.WriteLine(rock.Identifier); 

EDIT:

Here is the script.

Entity is a three-dimensional object. I am writing server software that has a list of such objects. The server manually serializes the list and sends it to the client. Since performance is very important here, I am not sending a type name. Each entity type has a unique identifier, so when a client receives data, it can effectively deserialize it.

To create an instance of an object, I do something like:

 Entity entity = EntityRepository.Instance.CreateNew(identifier); 

The EntityRepository class is as follows:

 public sealed class EntityRepository { private static readonly Lazy<EntityRepository> lazy = new Lazy<EntityRepository>(() => new EntityRepository()); IDictionary<ushort, Func<Entity>> _repo; private EntityRepository() { _repo = new Dictionary<ushort, Func<Entity>>(); } public static EntityRepository Instance { get { return lazy.Value; } } public Entity CreateNew(ushort id) { return _repo[id](); } public void Add<T>(ushort id) where T : Entity, new() { _repo.Add(id, new Func<Entity>(() => { return new T(); })); } } 

The current Add<T> method has a parameter that represents the identifier.

But how would I write an Add<T> method that has no parameters - that automatically recognizes the identifier?

So, I was thinking about adding an attribute to a nested Entity :

 [Identifier(1000)] public class Rock : Entity { } 

and a static property that returns the value of the Identifier attribute.

Then the Add<T> method without parameters will look something like this:

 public void Add<T>(ushort id) where T : Entity, new() { _repo.Add(T.Identifier, new Func<Entity>(() => { return new T(); })); } 

Note that in this case, I could just do T.GetType() to get the attribute, but that is not the point. How to do this in a static property, Entity.Identifier ?

+7
source share
4 answers

In principle, you cannot.

The Rock.Identifier call will be decided by the compiler on Entity.Identifier - there simply is no context for searching for the type.

A call to Rock.Identifier will not compile because you are trying to access a static element through a variable.

The best workaround will depend on the actual scenario - if you sent a message, I would suggest creating a static method in another place that took the type as a parameter.

Actually, you can fake it really horribly for your specific scenario using the Rock compile time type:

 public static class NastyExtensions { public static ushort GetIdentifier<T>(this T actualValueIsIgnored) { Type type = typeof(T); ... code as before } } 

Then:

 Rock rock = new Rock(); Console.WriteLine(rock.GetIdentifier()); 

But that would not be polymorphic. For example:

 Entity rock = new Rock(); Console.WriteLine(rock.GetIdentifier()); // Bang! T would be Entity here 

You can change the extension method to call GetType() , of course ...

+10
source

Static methods are not polymorphic in C # - you cannot override this implementation for subclasses.

EDIT: Essentially, as John Skeet points out, the C # compiler will handle the call to SubType.StaticMember as the equivalent of BaseType.StaticMember (unless, of course, the subtype provides a new, hiding member with the same name). Therefore, this code will always be run โ€œin contextโ€ of type Identifier , and there is no way to improve it:

 Type currentType = typeof(Identifier); 

Personally, I donโ€™t like the fact that C # even allows you to access static members through "subtypes" - it just sets up unpleasant errors and misunderstandings.

+7
source

The easiest way is to use generics:

 [Identifier(1000)] public class Rock : Entity<Rock> { } public abstract class Entity<T> { public static ushort Identifier { get { // How do I get here the current type of the object? Type currentType = typeof(T); foreach (IdentifierAttribute attribute in currentType.GetCustomAttributes(true)) return attribute.Identifier; throw new EntityException("No identifier has specified for this type of entity."); } } } 

That way, when you call Rock.Identifier , the compiler will allow its Entity<Rock>.Identifier . An example of the use of this template is performed in Castle ActiveRecord.

0
source

C# does not support polymorphism for static members. Static elements cannot be virtual or included in interfaces. Thus, you cannot easily group classes, even if all of them have a static member with the same name and signature.

0
source

All Articles