Base Class Enum Value from Derived Class? - c#

Is it possible to get the enum value of a base class, from a derived class, without using reflection ?
The code below using Reflection, which seems a bit of overkill to get a base class field value from an object instance.
using System;
namespace Seans
{
public class BaseClass
{
public enum eEnum{a, b, c}
}
class Program
{
static void Main(string[] args)
{
DerivedClassA newObject = new DerivedClassA();
TraverseTheObjectHierachyForTheTaskListEnum(newObject.GetType());
Console.ReadLine();
}
public static Type GetTaskListType(Type type)
{
// Handle the cases where our enums are defined in the base class
return TraverseTheObjectHierachyForTheTaskListEnum(type);
}
private static Type TraverseTheObjectHierachyForTheTaskListEnum(Type type)
{
foreach (Type nestedType in type.GetNestedTypes())
{
if (nestedType.IsEnum)
{
// Enum Name, now you can get the enum values...
Console.WriteLine(nestedType.FullName);
return nestedType;
}
}
if (type.BaseType != null)
{
return TraverseTheObjectHierachyForTheTaskListEnum(type.BaseType);
}
return null;
}
}
}

So, not quite clear on exactly what you're looking for since there are really no fields in BaseClass, just the enum type definition. Either of these:
Enum.GetValues(typeof(BaseClass.eEnum));
or
Enum.GetValues(typeof(DerivedClassA.eEnum));
will give you the values of the enumeration. If you don't know the name of the enumeration at compile time, then reflection is the only way to go.

Your above code does not get a field value, but rather the type objects of all nested types.
The recursion in the method TraverseTheObjectHierachyForTheTaskListEnum is necessary, beacuse type.GetNestedTypes() will only return the types of the actual type provicded (that is DerivedClassA), but not of any types nested in its base classes.
You can easily verify this behaviour by stepping through your code with the debugger. You won't get any nested types for DerivedClassA, but for the base class type.GetNestedTypes() will return the enum.

Related

value.GetType().IsSubClassOf(ClassBase) give me the error of "'ClassBase' is a type, which is not valid in the given context"

So am trying to check that a property is derived from a base class before storing it in the backing field. However I get the following syntax error 'ClassBase' is a type, which is not valid in the given context for line value.IsSubclassOf(ClassBase) which makes no sense since ClassBase is a Type and IsSubclassOf is expecting a type.
MCV example below
using System;
namespace QuestionIsSubClassOf
{
class Program
{
static void Main(string[] args)
{
var DataStorageClass = new DataStorageClass();
var DerivedClassA = new ClassDedrivedA();
DataStorageClass.TypeOfClassBase = DerivedClassA.GetType();
}
}
public class DataStorageClass
{
private Type _typeOfClassBase;
public Type TypeOfClassBase
{
get { return _typeOfClassBase; }
set
{
if (value.IsSubclassOf(ClassBase))
{
_typeOfClassBase = value.GetType();
}
else
{
throw new ArgumentOutOfRangeException($"{nameof(TypeOfClassBase)} must be a subclass of {nameof(ClassBase)}");
}
}
}
}
public class ClassBase
{
}
public class ClassDedrivedA : ClassBase
{
}
public class ClassDedrivedB : ClassBase
{
}
}
You need to use the typeof operator in C#.
if (value.IsSubclassOf(typeof(ClassBase)))
{
_typeOfClassBase = value.GetType();
}
else
{
throw new ArgumentOutOfRangeException($"{nameof(TypeOfClassBase)} must be a subclass of {nameof(ClassBase)}");
}
The typeof operator returns a Type object which corresponds to the type it was passed as an argument. When you're working on an instance you may not necessarily know what that type is so typeof cannot be used, which is why the GetType() function exists on the object class.
EDIT:
I'd also like to check if you mean to use IsSubclassOf or whether you actually want to use IsInstanceOfType / IsAssignableFrom.
IsSubclassOf does not return true if you're comparing against the same type. Ie
typeof(Type1).IsSubclassOf(typeof(Type1)) //returns false
If you're always comparing instances against a base type then you can use IsInstanceOfType, otherwise you can use IsSubclassOf with an additional check for ==. Alternatively their's IsAssignableFrom but their may be caveats with that. I'd always advice reading the documentation - MSDN in this case.
EDIT 2021-03-14:
I know this is an old question, but with newer versions of C# you can use pattern matching syntax which is much nicer.
// `is` will match for base and derived types
if(value is ClassBase)
_typeOfClassBase = value.GetType();
else
throw new ArgumentOutOfRangeException(...);

Validation against the non generic attribute of a generic type

I want to validate a class, that has a property of a generic type:
class Foo
{
[ValidHistoryDate]
public MyType<string> bar;
[ValidHistoryDate]
public MyType<int> baz;
[ValidHistoryDate]
public MyType<float> bat;
}
class MyType<T>
{
public string date;
public T property;
}
The generic type also contains a date, attribute (string), that should be validated against a valid date, so I wrote this function to do this:
public class ValidHistoryDateAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value == null)
return true;
var v = (List<MyType<object>>)value;
bool valid = true;
foreach (var f in v)
{
if (!Regex.Match(f.Date, #"^[0-9]{2}\.[0-9]{2}\.[0-9]{4}$").Success)
valid = false;
}
return valid;
}
}
The validation does not care about the property "property", but it should care about the string.
Unfortunately the cast fails:
var v = (List<MyType<object>>)value;
I mean: Of course it does, because "object" is not the real type. I want to use the validation attribute for all types and in the validation I actually do not even care about "property".
Any way to solve this in a nice way? I do not want to add a ValidHistoryDateAttribute for every possible type.
If I were to do this I would add a non-generic base type into your code:
public class ValidatableObject
{
public string date;
}
And then my class would be:
class MyType<T> : ValidatableObject
{
public T property;
}
Your validation code would then refer to the base class which makes things a lot simpler.
It looks like you are actually trying to cast something of type List<GenerericHistory<T>> which will run into Variance problems. If you are assuming you are using my base class the incoming item cannot easily be converted to List<ValidatableObject> - to see why consider that the actual list should only allow adding of GenerericHistory<T> (where T is a specific type) objects whereas a List<ValidatableObject> would allow adding of GenerericHistory<T> objects of any type. Thus the cast is not allowed.
If you were to change the list to an IEnumerable<GenerericHistory<T>> then you would be able to cast to IEnumerable<ValidatableObject>. The reason is that this time we have a readOnly object so all we are doing is getting out objects of type ValidatableObject and since know that the actual class will only ever return GenerericHistory<T> (for specific T) we also know it always returns of type ValidatableObject and thus this time the cast is allowed.
The last bit is based partly on speculation since your code seems to be inconsistent with regards to the use of List<T> in your code. I assume the validator is correct that a property on your validatable object is a list but obviously I have no idea if that List can be changed, etc.

Getting Nested Types from Higher in Hierarchy in C#

I have a few classes called SortMethod which inherit from an abstract class called ASortMethod. Each of these classes is nested in another class. Right now, I'm dealing with the SortMethod inside of a class called CitationCollection.
There's another class I'm dealing with called CustomSortDictionary. This has to handle the given SortMethod type, but it's unknown which SortMethod type will be given, so I store a variable Type sortMethod in CustomSortDictionary.
This means I unfortunately have to deal with lots of messy reflection. Within the given Type sortMethod, there are two main things I'm looking to access. The first I was able to access using the below code, but the second I'm having trouble getting to.
BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
// Accessing the first
MethodInfo m = SortMethod.GetMethod("ConstructCustomSortMethods", bindingFlags);
m.Invoke(null, null);
// Accessing the second
IDCollection customSort = (IDCollection)SortMethod.GetNestedType("CustomSort", bindingFlags).GetField("Methods").GetValue(null);
I've tried a few different combinations of BindingFlags to try to get to the nested type in the second piece of code, but I can't access it. I think the issue is that SortMethod.CustomSort.Methods is declared within ASortMethod, which is one step up the hierarchical ladder from CitationCollection.SortMethod.
How would I properly access this second item using reflection?
See this link for the full code.
UPDATE:
I found this from Microsoft's website, which may explain my issue:
BindingFlags.FlattenHierarchy
Specifies that public and protected static members up the hierarchy should be returned. Private static members in inherited classes are not returned. Static members include fields, methods, events, and properties. Nested types are not returned.
Your sort method type looks like this right?
public enum SortType { Ascend, Descend, FlyingTriangle }
You may want to use an interface so that all methods implementing it are required to either accept or reject a requested sort.
Example
public interface ISortable
{
public bool IsValidContext(object record, SortType type);
}
public class SortAlpha : ISortable
{
public bool IsValidContext(object record, SortType type)
{
return type == SortType.Ascend ? true : false; // example
}
}
public class SortBeta : ISortable
{
public bool IsValidContext(object record, SortType type)
{
return type == SortType.Descend && record is HtmlDocument; // example
}
}
You can have a method iterate trough the classes implementing the interface to find and return the right one.
Since the type CustomSort is always nested in ASortMethod you could just get it directly:
((IDCollection)typeof(ASortMethod.CustomSort).GetField("Methods").GetValue(null)).Add(ref name);
When you can not for some reason you could walk up the base types until you reach object to find the enclosing type of CustomSort
((IDCollection)FindBase(SortMethod).GetNestedType("CustomSort", bindingFlags).GetField("Methods").GetValue(null)).Add(ref name);
static Type FindBase(Type t)
{
if (t.BaseType != typeof (object))
return FindBase(t.BaseType);
return t;
}

C# determining generic type

I have several templated objects that all implement the same interface:
I.E.
MyObject<datatype1> obj1;
MyObject<datatype2> obj2;
MyObject<datatype3> obj3;
I want to store these objects in a List... I think I would do that like this:
private List<MyObject<object>> _myList;
I then want to create a function that takes 1 parameter, being a datatype, to see if an object using that datatype exists in my list.... sorta clueless how to go about this. In Pseudo code it would be:
public bool Exist(DataType T)
{
return (does _myList contain a MyObject<T>?);
}
Some Clarification....
My interface is IMyObject<T>, my objects are MyObject<T>. I have a new class MyObjectManager which I need to have a List of MyObject<T> stored within. I need a function to check if a MyObject<T> exists in that list. The type T are datatypes which were auto-generated using T4.... POCO classes from my Entity Data Model.
You can make a generic function:
public bool Exists<T>() where T : class {
return _myList.OfType<MyObject<T>>().Any();
}
Note that this requires that you know T at compile-time.
If all you have is a System.Type object at runtime, you'll need to use reflection:
public bool Exists(Type t) {
var objectOfT = typeof(MyObject<>).MakeGenericType(t);
return _myList.Any(o => o.GetType() == objectOfT);
}
Note, however, that a List<MyObject<object>> cannot hold a MyObject<SomeType>.
You need to change the list to a List<object>, or make MyObject implement or inherit a non-generic type and make the list contain that type.
How about an extension method?
public static bool HasAny(this IEnumerable source, Type type) {
foreach (object item in source)
if (item != null && item.GetType().Equals(type))
return true;
return false;
}
Usage:
bool hasDataType1 = myList.HasAny(typeof(MyObject<datatype1>));
Note that if you don't want to have to type out typeof(...) -- i.e., if you basically want your Exist method to only care about objects of type MyObject<T>, I'd go with something like SLaks's answer:
public static bool Exist<T>(this IEnumerable source) {
return source.OfType<MyObject<T>>().Any();
}
Also, SLaks is right that you really can't have a List<MyObject<object>> that's full of anything other than objects of type MyObject<object> or some derived class (and MyObject<datatype1>, etc. do not derive from MyObject<object> -- generics don't work that way).
Another way I might suggest to work around the whole "you can't get the type of a generic class using a System.Type object without using reflection" issue would be this: Make your MyObject<T> implement a non-generic interface, like this:
public interface IMyObject {
Type DataType { get; }
}
public class MyObject<T> : IMyObject<T>, IMyObject {
public Type DataType {
get { return typeof(T); }
}
}
Then your list could be a List<IMyObject> (the non-generic interface) and your Exist method could look like this:
public static bool Exist<T>(this IEnumerable source, Type type) {
return source.OfType<IMyObject>().Any(x => x.DataType.Equals(type));
}
Since they all implement the same interface, instead of casting them to object and calling GetType (which can be expensive) why not add a property to your interface called class name (or something)? Then you can use the linq in order to grab that property. And don't forget using System.Linq
using System.Linq;
public bool Exist(List<IMyInterface> objects, IMyInterface typeToCheck)
{
return objects.Any(t => t.ObjectName == typeToCheck.ObjectName);
}

Get the CustomAttributes of a specific member

Is there any way to get the custom attributes of a specific object I am receiving in a method?
I do not want nor can to iterate over Type.GetMembers() and search for my member. I have the object, which is also a member, that has the attribute.
How do I get the attribute?
class Custom
{
[Availability]
private object MyObject = "Hello";
private void Do(object o)
{
//does object 'o' has any custom attributes of type 'Availability'?
}
//somewhere I make the call: Do(MyObject)
}
No. Objects don't have attributes - members do. By the time you're in the "Do" method, there's no record of the fact that you called Do(MyObject) vs Do(MyOtherFieldWhichHasTheSameValue).
If you need to look up the attributes on a member, you'll basically have to pass in the relevant MemberInfo, not what it happens to evaluate to.
You cannot do this without at least 1 Reflection call. After that, save the value somehow.
Example:
abstract MyBase
{
public string Name;
protected MyBase()
{
//look up value of Name attribute and assign to Name
}
}
[Name("Foo")]
class MyClass : MyBase
{
}

Categories