I have a class which uses generic properties. For example:
class Person
{
public MyGenericProperty<string> Field1
{
get { return field1; }
set { field1 = value; }
}
private MyGenericProperty<string> field1= new MyInheritedGenericProperty<string>("Alan1");
}
I want to use this class with reflection at another class and i have a method like that
public void DoSomethingWithProperty(object sourceobject)
{
foreach (var aProperty in sourceobject.GetType().GetProperties())
{
*if(aProperty.PropertyType == typeof(MyGenericProperty<>))*
{
*var obj = (MyGenericProperty<>)aProperty.GetValue(sourceobject, null);*
}
}
return null;
}
I have two problem
1- How can do type check of generic property. In that example code of if(aProperty.PropertyType == typeof(MyGenericProperty<>)) does not work.
2- T of MyGenericProperty could be any class and how can cast MyGenericProperty class without knowing T by reflection as
var obj = (MyGenericProperty<>)aProperty.GetValue(sourceobject, null);
Thank for helps.
Firstly, it's important to understand that you don't have a "generic property" - there's no such thing. You have a property whose type is a generic type... and that's not the same thing. (Compare that with a generic type or a generic method, each of which is genuinely generic in terms of introducing new type parameters.)
You can test it using this code:
if (aProperty.PropertyType.IsGenericType &&
aProperty.GetGenericTypeDefinition() == typeof(MyGenericProperty<>))
But as for the casting - it depends on what you want to do with the value afterwards. You may want to declare a non-generic base type of MyGenericProperty<> containing all the members which don't depend on the type parameter. I'd typically give that the same name as the generic type (e.g. MyGenericProperty) just without giving it type parameters. Then if you only need one of those members, you can use:
if (aProperty.PropertyType.IsGenericType &&
aProperty.GetGenericTypeDefinition() == typeof(MyGenericProperty<>))
{
var value = (MyGenericProperty) aProperty.GetValue(sourceObject, null);
// Use value
}
But then in that case you could use Type.IsAssignableFrom anyway:
if (typeof(MyGenericProperty).IsAssignableFrom(aProperty.PropertyType))
{
var value = (MyGenericProperty) aProperty.GetValue(sourceObject, null);
// Use value
}
If these hints don't help you, please give more details of what you're trying to do.
Related
This should be simple, but I keep running into problems with this. I have a generic class Csvs<T>with a method that returns a type List<T> through a Property called Dockets. (The method reads CSV files and returns the list of the records in that CSV file. T is the type of that CSV file, which is defined in a series of models, which contain the header row as Properties)
In my calling class (which I cannot make generic), I have a switch statement based on an enum that contains the names of the classes I use in T.
switch (_userInput.CsvType)
{
case CsvType.Type1:
var csvType1 = new Csvs<Type1>(_userInput);
_dockets = csvType1.Dockets;
break;
case CsvType.Type2:
var csvType2 = new Csvs<Type2>(_userInput);
_dockets = csvType2.Dockets;
break;
case CsvType.Type3:
var csvType3 = new Csvs<Type3>(_userInput);
_dockets = csvType3.Dockets;
break;
// more cases here [...]
default:
throw new ArgumentOutOfRangeException();
}
(It would be nice if I could find a better way than using this switch, too, but it works for now.)
What does not work, or what I do not know how to do is, how to declare _dockets? Since T could be any of the types. I've tried extracting an interface ICsvs and have the class inherit it, and then declare
var _dockets = new List<ICsvs>;
But this throws an error, that I can't implicitly convert the List<Type1> to a List<ICsvs>.
And I can't cast the List to a type List<ICsvs>. (Then I get the next exception)
Cannot convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
The same happens if I use an abstract class.
So, how do I store the returned List in the calling class? How do I declare a field or property that can hold any of the types?
The simplest way to achieve this is to make all of your types implementing ICsv, like this:
interface ICsv { }
class CsvType1 : ICsv { }
class CsvType2 : ICsv { }
class Csvs<TCsvModel>
where TCsvModel: ICsv
{
public Csvs(IList<TCsvModel> csvModel)
{
this.Dockets = csvModel;
}
public IList<TCsvModel> Dockets { get; private set;}
}
So you can use this like:
IEnumerable<ICvs> dockets;
var cvsType1 = new Csvs<CsvType1>(_input);
dockets = cvsType1.Dockets
var cvsType2 = new Csvs<CsvType2>(_input);
dockets = cvsType2.Dockets
The most meaningful/polymorphic thing you can do is make the Dockets property return an interface describing what you do with them. Depending on your requirements, that may or may not be feasible - but you have little other option. As I commented, Generics really only works well when you know the type at compile-time.
By way of an example. An interface
public interface IDockets
{
void DoSomethingWithRecords();
}
A generic implementation which will be returned from your Csvs class
public class Dockets<T> : IDockets
{
private IEnumerable<T> dockets;
public Dockets(IEnumerable<T> dockets)
{
this.dockets = dockets;
}
public void DoSomethingWithRecords()
{
foreach(var docket in dockets)
Console.WriteLine(docket); // do whatever
}
}
This class would then be returned from your Csvs class Dockets property
public class Csvs<T>
{
private List<T> parsedDockets; // assume you have something like this:
public IDockets Dockets{ get { return new Dockets(parsedDockets); } }
}
And your calling code
IDockets dockets = null;
switch (_userInput.CsvType)
{
case CsvType.Type1:
var csvType1 = new Csvs<Type1>(_userInput);
dockets = csvType1.Dockets;
break;
// Snip //
}
dockets.DoSomethingWithRecords();
I think for what I was after, that is, storing the return value for later use, dynamic is the best answer (Thank you #Rahul). I can worry about the type later. Thank you all for your help.
dynamic _dockets;
then switch-case through the returns.
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.
Is it possible to check if the list contains an object of given (but dynamic) type, derrived from same basic abstract class?
The main problem is not about the list, but about comparing types itself.
In single variables and static variables, it's easy:
if(someVariable is int)
Checking the list with static type is also easy, like:
SomeList.OfType<int>().Any()
or
(from _Object in SomeList.OfType<int> where _Object is int select _Object).Count() == 0
but I cant't handle it if the type I want to check is dynamic, f.e. passed as method parameter:
abstract class BasicClass;
class DerivativeOne : BasicClass { }
class DerivativeTwo : BasicClass { }
// in main:
List<BasicClass> _List = new List<BasicClass>();
DerivativeOne a = new DerivativeOne();
DerivativeTwo b = new DerivativeTwo();
DerivativeOne c = new DerivativeOne();
if(!CheckIfTypeExistsInList(a, _List)
{
_List.Add(a);
}
if(!CheckIfTypeExistsInList(b, _List)
{
_List.Add(b);
}
if(!CheckIfTypeExistsInList(c, _List)
{
_List.Add(c); // this is what I don't want to happen,
// because I already have one object of type DerivativeOne in my list.
}
// the function:
bool CheckIfTypeExistsInList(BasicClass pObject, List<BasicClass> pList)
{
/// few attempts:
pList.OfType<(pObject.GetType()>().Any(); // attempt one, error
return (from _Object in SomeList.OfType<(pObject.GetType())> where _Object is int select _Object).Count() == 0; // attempt two, error
}
PS. I am aware that the code doesn't look neat, but I tried to show just the problem itself, skipping extra logic and stuff.
PS2. I am aware that the solution to the problem would be just to put some attribute to BasicClass and make each derivative to have unique value of the attribute, but still - I'm not looking for another route to solve the problem, I'm just interested if it's possible to do it "this" way.
When the type is known only at runtime, you cannot use it in a generic without using reflection. However, your task is simpler than that - you can use type equality to achieve the results that you want:
Type targetType = pObject.GetType();
if (SomeList.Any(o => targetType.Equals(o.GetType()))) {
...
}
I am trying to cast an object using generic arguments in C# like
(foo<mypara>)obj where the mypara is a generic argument.
public class foo<T>
{
public string name {get;set;}
public func<T> value {get;set;}
}
var mypara = myfoo.GetType().GetGenericArguments();
where the value of mypara.Name is "int" or "string", which is actually a string representation of the type.
But how can I get the real type of mypara?
A code example would be helpful, however I think all you need is obj.GetType()? That is how you get the type of an object.
Use reflection. GetType() on any object will get the name of the type. More reflections are necessary to make it that object type.
You can do it like this:
if (value != null)
{
if (value.GetType().IsGenericType == true
&& value.GetType().GetGenericArguments().Length >= 0)
{
IList _valuesList = null;
if (value.GetType().GetGenericArguments()[0].ToString().ToLower().Contains("int"))
{
_valuesList = value as List<int>;
}
else if (value.GetType().GetGenericArguments()[0].ToString().ToLower().Contains("decimal"))
{
_valuesList = value as List<decimal>;
}
else if (value.GetType().GetGenericArguments()[0].ToString().ToLower().Contains("double"))
{
_valuesList = value as List<double>;
}
else if (value.GetType().GetGenericArguments()[0].ToString().ToLower().Contains("string"))
{
_valuesList = value as List<string>;
}
}
}
Ref:
Get generic instance generic type using reflection
Reflection a properties of type of generic list
Reflection and generic types
Every InfringementEntity has a type.
foreach (InfringementEntity ie in _infCol.InfCollection.Select(r=>r).Distinct())
{
InfringementLodgementEntity.InfringementCollection.InfCollection.Add(ie);
}
InfringementLodgementCollection.InfringementLodgementEntities
.Add(InfringementLodgementEntity);
I need to select all Infringement Entity with a different type and insert them in a new InfringementLodgementEntity. And then add this InfringementLodgementEntity in InfringementLodgementCollection.
Question is how would I select infringementEntity with different types add them in a new InfringementLodgementEntity.
You should implement an IEqualityComparer<InfringementEntity> checking for the type, and use the Distinct overload that is accepting such a comparer.
If I understand your question, you can use OfType().
var theInfringementEntitiesYouWant = _infCol.InfCollection.OfType<TheTypeYouWant>().Distinct();
I left out .Select(r=>r) because it wasn't doing anything useful.
public abstract class BaseClass
{
private Type _classType;
public Type ClassType
{
get
{
return _classType;
}
set
{
_classType= value;
}
}
public abstract Type GetType();
}
public class InheritedClass: BaseClass
{
public override Type GetType()
{
if (ClassType == null)
{
ClassType = typeof(InheritedClass);//ie SingleInfringement or DblInfringment
}
return ClassType;
}
}
The simplest way I've found to deal with this is just have an abstract method GetType() in your base class which by definition must be overridden in your inherited class.
Reflection is rather expensive and should be used sparingly in most cases. So when we do use it we just store the result of our reflection.
This then allows us to do:
var entities = _infCol.InfCollection.Where(w => w.GetType() == typeof(DesiredType) );
from here you can do what you want, a bulk insert into another collection or whatever.