I'm pretty new to reflection in C#. I want to create a specific attribute that I can use with my fields, so I can go through them all and check that they are initialized properly, instead of writing these checks every time for every field. I think it would look something like this:
public abstract class BaseClass {
public void Awake() {
foreach(var s in GetAllFieldsWithAttribute("ShouldBeInitialized")) {
if (!s) {
Debug.LogWarning("Variable " + s.FieldName + " should be initialized!");
enabled = false;
}
}
}
}
public class ChildClass : BasicClass {
[ShouldBeInitialized]
public SomeClass someObject;
[ShouldBeInitialized]
public int? someInteger;
}
(You may notice that I intend to use it Unity3d, but there's nothing specific to Unity in this question — or at least, it seems so to me). Is this possible?
You can get this with a simple expression:
private IEnumerable<FieldInfo> GetAllFieldsWithAttribute(Type attributeType)
{
return this.GetType().GetFields().Where(
f => f.GetCustomAttributes(attributeType, false).Any());
}
Then change your call to:
foreach(var s in GetAllFieldsWithAttribute(typeof(ShouldBeInitializedAttribute)))
You can make this more useful throughout your app by making it an extension method on Type:
public static IEnumerable<FieldInfo> GetAllFieldsWithAttribute(this Type objectType, Type attributeType)
{
return objectType.GetFields().Where(
f => f.GetCustomAttributes(attributeType, false).Any());
}
You would call this as:
this.GetType().GetAllFieldsWithAttribute(typeof(ShouldBeInitializedAttribute))
Edit: To get private fields, change GetFields() to:
GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
And to get the type (inside your loop):
object o = s.GetValue(this);
Related
Following this question, it is possible to create a type and an instance form it dynamically like this:
var type = typeof(AnimalContext<>).MakeGenericType(a.GetType());
var a_Context = Activator.CreateInstance(type);
Great.
However, what I want to do instead of creating an instance of a determined type with Activator.CreateInstance(type);is to use a dynamic created type to declare a variable, and assign an instance to my dynamically created type.
Kind of:
myDynamicallyCreatedType variableName = figuredTypeInstace;
But I cannot use the created type(var type = typeof(AnimalContext<>).MakeGenericType(a.GetType()); for declarations. Is that possible?
Edit:
Short scenario explanation where the need came up. I need to call a method that will be called from a "topManager", this topManager holds the respective instance of the types type1Manager and type2Manager that implement the same base interface IMyInterface method ImplementedMethod.
What I am trying to do, could be solved with ifs, like this:
private int HandleInstance(Type itemType, //other args) {
if (itemType == Type.type1) {
topManagerInstance.manager1Instance.ImplementedMethod(//args):
}
elseif (itemType == Type.type2) {
topManagerInstance.manager2Instance.ImplementedMethod(//args):
}
...not meaningful code
{
But, I was wondering if it could be solved handling types to avoid the ifs, like (caps used to spot the key of the question out, not to shout):
private int HandleInstance(Type itemType, //other args) {
Type managerType = itemType == Type.type1 ? typeof(manager1Type) :
typeof(manager2Type);
Type[] managerTypeArray = { managerType, typeof(int) };
var myDynamicallyCreatedType = typeof(IMyInterface<,>).MakeGenericType(managerTypeArray);
//KEY OF THE QUESTION. THIS IS WHAT I AM ASKING FOR
//assign created variable to dynamic created type to call respective method
myDynamicallyCreatedType variableName = topManagerInstance.type1Manager;
//base type. any type1ManagerType or type2ManagerType to be assigned, as
//they inherit from the same IMyInterface<,>, and the type created is
//generic
variableName.ImplementedMethod(//args):
}
It seems like you're just looking to map an enum value to a function call in a specific implementation. One way to do that is to have a factory class that handles it with a Dictionary used as a map. For example:
Given a setup something like this:
// The enum you use for mapping
public enum Thing
{
Foo,
Bar
}
// The various implementations...
public interface ISomeInterface
{
void SomeMethod();
}
public class Foo : ISomeInterface
{
public void SomeMethod() => Console.WriteLine("Foo method!");
}
public class Bar : ISomeInterface
{
public void SomeMethod() => Console.WriteLine("Bar method!");
}
Now you could have a factory that looks like this:
public class MyThingFactory
{
private Dictionary<Thing, ISomeInterface> _registry;
public MyThingFactory()
{
_registry = new Dictionary<Thing, ISomeInterface>
{
{Thing.Foo, new Foo()},
{Thing.Bar, new Bar()},
};
}
public void RunMethod(Thing thing)
{
if(!_registry.TryGetValue(thing, out var item))
{
throw new ArgumentOutOfRangeException(nameof(thing));
}
item.SomeMethod();
}
}
And call it like this:
// You may want to make this static for performance reasons since you won't recreate
// the dictionary every time
var factory = new MyThingFactory();
factory.RunMethod(Thing.Foo);
factory.RunMethod(Thing.Bar);
//Output:
//Foo method!
//Bar method!
I have about 1000 classes in which i need to count the number of properties of. I have the following code:
public static int NumberOfProperties()
{
Type type = typeof(C507);
return type.GetProperties().Count();
}
I could copy and paste this in to each class changing the typeof parameter but this seems a bit tedious.
Is there anyway to make an extensions method to do this by just doing var nop = C507.NumberOfProperties();?
Just to add to the answers suggesting an extension for object for completeness: you can also consider implementing an extension only for Type:
public static int GetPropertyCount(this Type t)
{
return t.GetProperties().Length;
}
and use it like this:
typeof(C507).GetPropertyCount();
The advantage is that you can get the number of properties directly from the type and do not have to create an instance first.
So you can write an extension method that uses object or one that uses type.
public static class ObjectExtensions
{
public static int GetNumberOfProperties(this object value)
{
return value.GetType().GetProperties().Count();
}
public static int GetNumberOfProperties(this Type value)
{
return value.GetProperties().Count();
}
}
Usage:
new C507().GetNumberOfProperties();
typeof(C507).GetNumberOfProperties();
However, you explicitly state two things:
I could copy and paste this in to each class changing the typeof
I have about 1000 classes
You'll likely not want to instantiate a 1000 classes or copy and paste typeof() 1000 times
In this case, you will want to read them all from the Assembly.
So something like:
typeof(SomeClass).Assembly.GetTypes().Select(x => new
{
x.Name,
PropertyCount = x.GetType().GetProperties().Count()
});
Where SomeClass is a class (doesn't matter which) where all the classes reside.
I just simply select them out into an anonymous object which contains the Types name and property count.
This:
typeof(SomeClass).Assembly
Is just a convience way to get the assembly. There are other ways.
Assembly.GetAssembly(typeof(Program)).GetTypes()
Assembly.GetCallingAssembly().GetTypes()
Assembly.Load("Some Assemble Ref").GetTypes()
You can do allsorts with the types that you find. If you select out the Type itself, you can instantiate it later using Activator.CreateInstance (if it has parameterless constuctor). You can also auto fill the properties with reflection as well.
It is impossible to have a static extension method as you imagine it. That being said, it would be possible to create a generic method in a helper class as follows.
public static int NumberOfProperties<T>()
{
Type type = typeof(T);
return type.GetProperties().Count();
}
Given a type SomeType it could be called as int n = NumberOfProperties<SomeType>().
You could make an extension method on object like this:
public static int PropertyCount(this object thing)
{
return thing.GetType().GetProperties().Count();
}
And use it on any object you like:
var x = "some string";
var numProps = x.PropertyCount();
If you want to have an extension method on object:
public static ObjectExtensions
{
public static int NumberOfProperties(this object value)
{
if (null == value)
throw new ArgumentNullException("value"); // or return 0
// Length: no need in Linq here
return value.GetType().GetProperties().Length;
}
}
...
C507 myObj = new C507();
// How many properties does myObj instance have?
int propCount = myObj.NumberOfProperties();
If you want to have an extesnion method on Type:
public static TypeExtensions
{
public static int NumberOfProperties(this Type value)
{
if (null == value)
throw new ArgumentNullException("value"); // or return 0
// Length: no need in Linq here
return value.GetProperties().Length;
}
}
...
// How many properties does C507 type have?
int propCount = typeof(C507).NumberOfProperties();
There are a couple of ways to do this that are variations of the same thing.
You can pass the Type as an argument to a method:
public static class Helper {
public static int NumberOfProperties(Type type)
{
return type.GetProperties().Count();
}
}
Which you would call like this:
// Imagine you have a class called MyClass
var result = Helper.NumberOfProperties(typeof(MyClass));
You use use the generic system in C# to make the syntax a little cleaner. That would look like this:
public static class Helper {
// Notice the argument was removed and
// the use of the "generic" syntax <T>
public static int NumberOfProperties<T>()
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
And you would call it like this:
var result = Helper.NumberOfProperties<MyClass>();
You could also use "Extensions" which allow you to call it as if it was a method that belonged to your classes.
public static class Helper {
// notice the `this` keyword before the parameter
// this is what tells C# that this is an extension method
public static int NumberOfProperties<T>(this T #this)
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
This will allow you to call the method like this:
var instance = new MyClass();
var result = instance.NumberOfProperties();
In this example I used the generic syntax so that it applies to any type of object. If you wanted to limit it to only objects that inherit from a specific interface or base class you would just change it from using the generic syntax to using the base class/interface. Like this:
public static class Helper {
// notice the type got changed from a generic <T>
// to specifying the exact class you want to "extend"
public static int NumberOfProperties(this MyBaseClass #this)
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
As #rené-vogt mentioned you can also create the extension method so that it extends the type Type instead. See his answer in this thread: https://stackoverflow.com/a/38455233/984780
You can make a generic extension method which can apply to all types:
public static int PropertyCount<T>(this T obj)
{
return typeof(T).GetProperties().Length;
}
This will apply to all types including value types (I.E. structs) which applying to object will not. Thanks to piedar for pointing out my mistake here, applying to object does still add this extension method to value types.
If your classed can implement an interface, then you can extend that interface.
public interface IExtensible {
}
class C507 : IExtensible {
}
public static int NumberOfProperties(this IExtensible extensible)
{
Type type = extensible.GetType();
return type.GetProperties().Count();
}
That being said, having hundreds of (generated?) classes looks like a bad solution to begin with.
This is what I am trying to get
(IList<Foo>)listPropertyInfo.GetValue(item)
This is how I get Foo type
listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]
This is what I tried but couldn't make it successfully
Convert.ChangeType(listPropertyInfo.GetValue(item), IList<listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]>)
and also this;
((typeof(IList<>).MakeGenericType(listPropertyInfo.GetValue(item).GetType().GenericTypeArguments.Single())))(listPropertyInfo.GetValue(item))
this is method where I am trying to implement
public static void trigger(IList<T> result)
{
foreach (var item in result)
{
foreach (var listPropertyInfo in typeof(T).GetProperties().ToList().FindAll(x => x.PropertyType.Name == typeof(IList<>).Name))
{
trigger((IList<Foo>)listPropertyInfo.GetValue(item));
}
}
}
I solved like this;
IList targetList = (IList)listPropertyInfo.GetValue(item);
Type foo = targetList.GetType().GenericTypeArguments.Single();
Type unboundGenericType = typeof(READ<>);
Type boundGenericType = unboundGenericType.MakeGenericType(foo);
MethodInfo doSomethingMethod = boundGenericType.GetMethod("trigger");
object instance = Activator.CreateInstance(boundGenericType);
doSomethingMethod.Invoke(instance, new object[] { targetList, f, properties });
If you use IList notation, Foo must be defined at compile time, you can't use expression that evaluates at runtime for Foo.
After reading your comments and and the code i would argue you are trying to do it at the wrong spot.
Here an example of how you could do this
public class MyGeneric<T>
{
public static void trigger(IList<T> result)
{
// do generic stuff where
// you do not need to know T
}
}
// this class does only explicit Foo related stuff
public class MyNONEGeneric
{
public static void trigger(IList<Foo> list)
{
// do some
}
}
class Program
{
static void Main(string[] args)
{
PersistentGenericBag<Foo> magicBag = myMagic<Foo>();
// call your generic which do some general list related stuff
MyGeneric<Foo>.trigger(list);
// call your none generic which do some foo related stuff
MyNONEGeneric.trigger(list);
}
}
like you can see i did some sort of "separation of concerns" / "single responsibility principle" here.
Every thing does only "one" thing. so if you are in need to change something you will know exactly where.
Also if you are working in a Team you can tell Person A to do the MyGeneric<T> and Person B to do the MyNONEGeneric
How can I use reflection to pass each list of "MyTypes" to a generic method with a constraint of T:MyDataObject?
public interface IAllMyTypes
{
List<FirstType> MyType1 { get; set; }
List<SecondType> MyType2 { get; set; }
List<ThirdType> MyType3 { get; set; }
}
FirstType, SecondType, and ThirdType inherit from MyDataObject (as demonstrated below), but have different properties.
public class FirstType : MyDataObject
{
//various properties
}
I've been unable to pass the data into a method with this signature:
void DoSomething<T>(IEnumerable<T> enumerable) where T : MyDataObject;
The error is that "type arguments can not be inferred."
Here is my unsuccessful attempt:
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
{
var x = propertyInfo.GetValue(allMyTypes) as IList;//im not sure what to do here
if(x==null) throw new Exception("still wrong");
DoSomething(x);
}
}
All of the code in DoSomething(..) works correctly if I provide the properties directly which looks like:
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
DoSomething(allMyTypes.MyType1);
DoSomething(allMyTypes.MyType2);
DoSomething(allMyTypes.MyType3);
}
If you want to use reflection, you can invoke your helper method using reflection, too:
You will have to obtain a MethodInfo to a generic method and create a generic method reflection handle to actually Invoke the method. The type T of the generic method needs to be obtained at runtime in that case.
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
var method = this.GetType().GetMethod("DoSomething", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
{
var x = propertyInfo.GetValue(allMyTypes, null);
if(x==null) throw new Exception("still wrong");
// obtain the type from the property - other techniques can be used here.
var genericMethod = method.MakeGenericMethod(new[] {propertyInfo.PropertyType.GetGenericArguments()[0]})
//execute the generic helper
genericMethod.Invoke(this, new[]{x});
}
}
public void DoSomething<T>(IList<T> list) where T : MyDataObject {
}
I'm struggling to find a case where you'd need to structure your data the way you did without over-complicating things. If you've found a legit case please comment and I'll update my answer to reflect your needs.
You can start with your base class, make it abstract and put an abstract method in it DoSomething
public abstract class MyDataObject{
public string SomeSharedProperty{get;set;}
protected abstract DoSomething();
}
public class FirstType: MyDataObject{
protected override DoSomething(){
Console.WriteLine(SomeSharedProperty);
}
}
public class Consumer{
public void DoSomethingWithAllMyTypes(List<MyDataObject> source)
{
source.ForEach(x=>x.DoSomething());
}
}
You could use the Linq method call Cast<T> to convert your list to the right type
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
{
var x = propertyInfo.GetValue(allMyTypes) as IEnumerable
if(x==null) throw new Exception("still wrong");
DoSomething(x.Cast<MyDataObject>());
}
}
I am trying to define an extension method that can return an object of a type defined by the call.
Desired Use: Cat acat = guy.GiveMeYourPet<Cat>();
Attempted implementation
I have no trouble defining generic methods like this:
public static T GiveMeYourPet<T>(Person a) { ... }
Cat acat = GiveMeYourPet<Cat>(guy);
or extension methods like this:
public static Cat GiveMeYourPetCat<P>(this P self) where P : Person, ... { ... }
Cat acat = guy.GiveMeYourPetCat();
But when I try to do what I really want:
public static T GiveMeYourPet<T, P>(this P self) where P : Person, ... { ... }
Cat acat = guy.GiveMeYourPet<Cat>();
The compiler expects GiveMeYourPet() to receive 2 type arguments (even though one is implicitly provided by calling the extension method on the object guy.
What can I do to make this work?
Note that I've also tried reversing the order in which the parameters are defined, but nothing changes:
public static T GiveMeYourPet<P, T>(this P self)
The following call also does not work, because you cannot have a method call in the type specifiation:
Cat acat = guy.GiveMeYourPet<guy.GetType(), Cat>();
The C# compiler type inference is not as sophisticated as you might hope. You have to explicitly specify both types in such a method:
void Main()
{
int i = 0;
bool b = i.GiveMeYourPet<bool, int>();
}
public static class MyExtensions
{
public static T GiveMeYourPet<T, P>(this P self)
{
return default(T);
}
}
If you want to avoid specifying both explicitly (and I wouldn't blame you), you might try to change your method to something like:
public static T GiveMeYourPet<T>(this IPetOwner self)
(with this interface, you shouldn't even need to know what the real type is; if you do, use as or is) Or even:
public static T GiveMeYourPet<T>(this object self)
(and use as or is)
If that's not an option, and the real type of guy (in your example) is not statically known (e.g. you just have him as an object), you'll probably have to use reflection, e.g.:
MethodInfo method = typeof(MyExtensions).GetMethod("GiveMeYourPet");
MethodInfo generic = method.MakeGenericMethod(typeof(Pet), guy.GetType());
generic.Invoke(guy, null);
If something like guy.GiveMeYour.Pet<Cat>(); would work you can build 2 levels similar to code:
public class GiveMeYourBuilder<P>
{
public P Me {get;set;}
public T Pet<T>() : where T: new()
{ return new T();}
}
public static PetExtensions
{
public GiveMeYourBuilder<P>(this P me)
{
return new GiveMeYourBuilder<P> { Me = me;}
}
}
You can't partially specify generic arguments, either they are all inferred or you have to specify them all. In this case, the closest you can get is probably to return an intermediate object which carries the generic Person type the extension method is called on, and define your Get methods on that:
public class GiveContext<T> where T : Person
{
public P MeYourPet<P>() where P : Pet
{
return default(P);
}
}
public static GiveContext<T> Give<T>(this T person) where T : Person
{
return new GiveContext<T>();
}
which you can use like:
var p = new Person();
Cat c = p.Give().MeYourPet<Cat>();
You can't do this, unfortunately. If the compiler can't figure them all out, you need to type out all the type arguments. The C# compiler isn't that smart. dynamic can help though:
public static T GiveMeYourPet<T>(this dynamic self)
{
//in here check that self meets your constraints using is, as, etc.
}