There's all kinds of really awesome info on how to iterate through all of the properties of a class. What I want to do, however, is iterate through them and instantiate each property as new in the constructor... The class is an aggregate class representing a collection of entity framework model objects/classes. I could instantiate each in turn but that is going to be huge and a problem for maintenance when I decide to add another table to the database...
public class ClsAggModel {
public ClsAggModel() {
foreach (PropertyInfo props in this.GetType().GetProperties()) {
props.SetValue = new props.GetType(); //problem here!
}
}
public clsItem1 pProp1{ get; set; }
public clsItem2 pProp2{ get; set; }
//...and so on
The problem is that the compiler doesn't seem to know what props is at this point:
The type or namespace name 'props' could not be found (are you missing
a using directive or an assembly reference?)
which seems kind of strange since I just i stantiated it in the loop signature. I could fill out each property and do the private variable and all that jazz but what good is reflection if you can't abuse it?
Any tips?
You can not create instance on base of .GetType() in this manner.
This will not work:
new props.GetType();
You should try using:
Activator.CreateInstance(props.GetType());
Based on already provided solutions your code should look like this:
public class ClsAggModel {
public ClsAggModel() {
foreach (PropertyInfo prop in this.GetType().GetProperties()) {
var newValue = Activator.CreateInstance(prop.GetType());
prop.SetValue(this, newValue);
}
}
public clsItem1 pProp1{ get; set; }
public clsItem2 pProp2{ get; set; }
Keep in mind that all properties types must allow dynamic creation, by providing a default constructor (it is automatically there, if other constructor is not defined).
Assuming you want to call a default created type use the activator like this
props.SetValue(this, Activator.CreateInstance(props.GetType()));
Note, this will still fail if there is no default constructor. Because you are using reflection your compiler can no longer check for this.
Note 2: Be vary carefully with abusing reflection. it's a sure way to shoot yourself in the foot sooner or later.
Update of course setvalue is a method, changed this
Related
I have a data class with several members
public interface IEquipmentHolder
{
ITypedServiceProvider<IGrabberChannel> VideoChannels { get; }
ITypedServiceProvider<IMicrophone> Microphones { get; }
ITypedServiceProvider<ISpeaker> Speakers { get; }
...
}
and a function
void visitChilds<T>(ITypedServiceProvider<T> childsList) where T : INamedComponent
{
...
}
In some place of my code, I want call the function for each field of the data class. So i do:
visitChilds(equipment.VideoChannels);
visitChilds(equipment.Microphones);
...
But, probably I am going to add some new fields in the data class and don't want to forget to fix these place after that.
My question: is it possible to to call generic function for each data member of the class using reflection? if it is not, can we put compile time check for new fields in the c# code?
How often are you going to add more fields and 'forget' to update calling code?
How fast are you going to find out that you've forgotten to add a call to visitChilds()?
How about IEquipmentHolder has only one property ITypedServiceProvider<INamedComponent> Items { get; }?
Reflection is slower than direct calls (maybe you should emit IL?) and the additional code may be just not worth the 'improvement', especially if it will be easy to spot that new set it not visited.
Also consider, that adding a new set of INamedComponents requires a breaking change to IEquipmentHolder interface and all implementations.
You could use the Expression framework to generate a lambda that will call visitChilds for each property on the interface.
You'd need to use reflection to generate the expression, but this would be a one off hit. After that you'd have a dynamically compiled lambda you could call that would be a lot quicker.
I've done something similiar before whereby I convert an instance of an object into a Dictionary<string,object> where each key is the name of a property and the value is the value of the property. We generated a lambda for each type we wanted to convert, and it worked really well.
If ITypedServiceProvider is covariant, i.e., declared like this,
ITypedServiceProvider<out T>
{
...
}
then you could have
IEquipmentHolder
{
IEnumerable<ITypedServiceProvider<INamedComponent>>
NamedComponents { get; }
}
then your could do
void VisitChildren(IEquipmentHolder equipment)
{
foreach(var provider in equipment.NamedComponents)
{
provider.SomeMemberOfITypedServiceProvider();
}
}
Intro
I'm working with the legacy code which contains two classes:
I have a class which stores its value of System.Object type.
(I named this class as DomainItem)
Its Identifier property refers to
enum which holds information what a type of DomainItem is (in the
context of business domain).
There is also a class which stores these
items as an Enumerable List. (DomainItems)
What's more:
I don't want to change these classes into generic. This code is very sensitive and not covered by tests.
In order to get DomainItem, I must get it from DomainItems.Items collection.
Code
The code for classes is equivalent as below:
public class DomainItem
{
public Identifier Identifier { get; set; } // Readonly in the "real" code
public object Value { get; set; }
}
public class DomainItems
{
public IEnumerable<DomainItem> Items { get; set; }
}
The question is
How can I extend these classes using generics, to resolve type of Value property in the compile time. Is it even possible?
Example case might be as following:
DomainItem price = new DomainItem { Value = 25.20d, Identifier = Identifier.Price };
// ....
double priceValue = price.ProperValue; // generic property of type T
Obviously, above code is conceptual and it shows what I want to achieve. Any suggestions how to resolve that? Is it even possible?
Edit
My idea is to create a new IEnumerable<DomainItem<T>> where the collection is populated from non-generic DomainItem objects. Since the type of DomainItem.Value is known, it should be possible to make such collection somehow.
There's no such thing as a generic property, but you could easily create a generic method:
public T GetValue<T>() { ... }
public void SetValue<T>(T value) { ... }
You could then check typeof(T) within the method to make sure that it was appropriate for your identifier, ideally having made the identifier read-only. (It would be better as a constructor argument - I wouldn't expect it to make any sense to have a domain item whose identifier changed over time.)
Alternatively, you could just make the type of the Value property dynamic instead of object, assuming you're using C# 4+ with .NET 4+. Then your example code would compile - but it would perform an implicit (dynamic) conversion to double at execution time. You wouldn't get much safety there, but it would compile...
Let's assume I have a class ClassWithMember
class ClassWithMember
{
int myIntMember = 10;
}
How do I get the default value 10 of the myIntMember member by System.Type?
I'm currently struggling around with reflections by all I retreive is the default value of int (0) not the classes default member (10)..
You can try something like this:
var field = typeof(ClassWithMember).GetField("myIntMember",
BindingFlags.Instance | BindingFlags.NonPublic);
var value = (int)field.GetValue(new ClassWithMember());
The trick here is to instantiate an instance.
Try creating an instance an retreive the value with reflection.
If you're in control of the code for ClassWithMember, you could take a completely different approach to this by using the [DefaultValue] attribute from System.ComponentModel. Basically, what you'd do is write something like this:
class ClassWithMember
{
public ClassWithMember()
{
SetDefaultValues();
}
[DefaultValue(5)]
public MyIntMember { get; set; }
}
And then have a function like this somewhere, perhaps in a base class:
public void SetDefaultValues()
{
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
{
DefaultValueAttribute a = prop.Attributes[typeof(DefaultValueAttribute)] as DefaultValueAttribute;
if (a == null)
continue;
prop.SetValue(this, a.Value);
}
}
So now, you have a situation where you can easily retrieve the default values using Reflection.
Keep in mind that this is going to be quite a lot slower due to the Reflection requirement, so if this code gets instantiated a lot, you'll probably want to find a different approach. Also, it won't work with non-value types, due to a limitation with the .NET Framework's attribute support.
You can still use Activator.CreateInstance to create a MonoBehaviour/ScriptableObject and check its values, if it's simply for the sake of checking the default Values. Make sure to use DestroyImmediate afterwards ;-)
Is there any way to do something like this?
public interface ISomething
{
}
public class SomethingThatImplementsISomething: ISomething
{
}
public class SomethingElse
{
public ICollection<ISomething> PropertyName{ get; set; }
}
I've tried it out, and it keeps failing. Any ideas?
ICollection<Models.Awardable> can not be converted to ICollection<IAwardable>.
What would happen if someone tried to add an IAwardable to the collection that wasn't a Models.Awardable?
Just instantiate a collection of IAwardable and add instances of Models.Awardable to it.
Make sure you have using System.Collections.Generic rather than just using System.Collections at the top of your compilation unit.
Edited to add:
Actually, this probably has to do with the fact that version of C# prior to 4.0 do not allow for covariance or contravariance for generics. In older versions, a generic field must be defined to use an exact data type, to avoid invalid reference type assignments.
Edited again:
Now that I see the actual error message that you are getting, the problem is not in the definition of the field, but in its use. You need to put an explicit cast in the assignment.
The auto-property
public ICollection<ISomething> PropertyName{ get; set; }
tries to create a backing-field of type ICollection<>, which will fail. Try something like:
public List<ISomething> PropertyName{ get; set; }
It sounds like what you're trying to do is this:
ICollection<SomethingThatImplementsISomething> collection = new List<SomethingThatImplementsISomething>();
somethingElse.PropertyName = collection;
If that's the case, then this is a generic variance issue. ICollection is not covariant in its element type. (Because it it were, you could now go somethingElse.PropertyName.Add(somethingDifferentThatsAlsoAnISomething); -- and you'd have added a SomethingDifferentThatsAlsoAnISomething to a list of SomethingThatImplementsISomething, which breaks type safety.)
You need to instantiate a collection of ISomethings:
ICollection<ISomething> collection = new List<ISomething>();
somethingElse.PropertyName = collection;
You can then add SomethingThatImplementsISomething objects to your heart's content:
somethingElse.PropertyName.Add(new SomethingThatImplementsISomething());
My question stems from MVC's SelectList (and previous generations). Basically the class takes in an IEnumerable and uses the members you define as strings.
How does it interface with the object (casting, reflection?)
(probably redundant) How does it lookup the members as a string.
This is one facet of C# that I have been interested in but could never find examples of :(
EDIT:
I ended up using DataBinder.Eval() from System.Web.UI
It still has the overhead of reflection but makes things easier by allowing you to pass the object and a string containing the hierarchy of the member you want. Right now that doesn't really mean much, but this project was designed to take in Linq data, so not having to worry about it down the road makes my life a tad easier.
Thanks everyone for the help.
While I don't know about its implementation for sure, I'd expect it to use reflection.
Basically you call Type.GetProperty or Type.GetMethod to get the relevant member, then ask it for the value of that property for a specific instance (or call the method, etc). Alternatively there's Type.GetMembers, Type.GetMember etc.
If you want to be able to use "Person.Mother.Name" or similar "paths" you have to do that parsing yourself though, as far as I'm aware. (There may be bits of the framework to do it for you, but they're not in the reflection API.)
Here's a short but complete example:
using System;
using System.Reflection;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
class Test
{
static void Main()
{
Person jon = new Person { Name = "Jon", Age = 33 };
ShowProperty(jon, "Name");
ShowProperty(jon, "Age");
}
static void ShowProperty(object target, string propertyName)
{
// We don't need no stinkin' error handling or validity
// checking (but you do if you want production code)
PropertyInfo property = target.GetType().GetProperty(propertyName);
object value = property.GetValue(target, null);
Console.WriteLine(value);
}
}
Yes, via reflection. Take a look at the Type class and associated methods. A good place to start might be here.
You can always look at MVC's source for examples too.