How can I store all the properties of a class in an array of objects? - c#-3.0

Let's say I've a class myClass which has few properties, such as property1, property2, perperty3, etc. Now, I'd like to populate an array with each of those properties so that, I can access each of them through its index. Is there an automatic way of doing so?
Here's an example from SportsStore (Pro ASPN.NET MVC/Steve Sanderson/Apress) on how to gather all the active controllers in the the 'Assembly'.
var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes()
where typeof(IController).IsAssignableFrom(t)
select t;
foreach(Type t in controllerTypes)
//Do something
I wonder if there is some thing like the one above I can use to collect (only) properties of a class and store them in a array, no matter each one's type value (int, string, or custom type)
I hope I was able to express myself clearly. Otherwise I can amend the text.
Thanks for helping.

You could use reflection:
var foo = new
{
Prop1 = "prop1",
Prop2 = 1,
Prop3 = DateTime.Now
};
var properties = TypeDescriptor.GetProperties(foo.GetType());
var list = new ArrayList();
foreach (PropertyDescriptor property in properties)
{
var value = property.GetValue(foo);
list.Add(value);
}
and LINQ version which looks better to the eye:
var list = TypeDescriptor
.GetProperties(foo.GetType())
.Cast<PropertyDescriptor>()
.Select(x => x.GetValue(foo))
.ToArray();

I got this from here:
foreach(Type t in controllerTypes)
{
foreach (MemberInfo mi in t.GetMembers() )
{
if (mi.MemberType==MemberTypes.Property)
{
// If the member is a property, display information about the property's accessor methods
foreach ( MethodInfo am in ((PropertyInfo) mi).GetAccessors() )
{
// do something with [am]
}
}
}
}

would the Type.GetProperties() method help you?

Related

Unable to print the values of an instance of my model

I know this is a very fundamental question but answer to this will solve many of my doubts.
val new_parent = ParentDetails(intent.extras.getString("name"),
intent.extras.getString("email"),
intent.extras.getString("parent_relation"),
intent.extras.getString("locationdata"))
println(new_parent.tostring())
The code above doesn't print the various fields and their values present in the class.
The ParentDetails is a model I have created with some fields that are initialized. The ParentDetails model:
class ParentDetails {
var parent_id: Int = 0
var parent_name: String = ""
var parent_email: String = ""
var parent_relation: String = ""
var parent_location: String=""
constructor(parent_name: String, parent_email: String, parent_relation: String,parent_location:String) {
this.parent_name = parent_name
this.parent_email = parent_email
this.parent_relation = parent_relation
this.parent_location = parent_location
}
public fun getparentId(): Int {
return parent_id
}
fun ParentDetailsprintme() {
println(parent_name)
println(parent_email)
println(parent_relation)
println(parent_location)
}
}
In fact, it prints null and accessing individual fields, it prints empty string(the way it was initialized).
How do we explain this?
As I understand your problem is that calling println(new_parent.tostring()) does not print what you would like to print in function ParentDetailsprintme.
First of all, you have a typo, the correct call would be new_parent.toString().
Note that it could have been simplified as println(new_parent).
It does not print that you defined in the ParentDetailsprintme method, as the method is not called.
What println(new_parent.toString()) prints, is actually the hashcode of the object, as this is the default behaviour of every object.
To make it work call it like println(new_parent.ParentDetailsprintme()) or override the toString() method for example as:
override fun toString() = "$parent_name $parent_email $parent_relation $parent_location"
then the following
val new_parent = ParentDetails("myName", "myEmail", "myParent_relation", "myLocationdata")
println(new_parent)
should print
myName myEmail myParent_relation myLocationdata
Kotlin's println function simply calls System.out.println(message) under the hood which will call String.valueOf() (e.g. String.valueOf(Object object) for objects, which will call the toString() method of the passed object).
/** Prints the given message and newline to the standard output stream. */
#kotlin.internal.InlineOnly
public inline fun println(message: CharArray) {
System.out.println(message)
}
Update ("Using data class method also works"):
If you make the class to be a data class:
data class ParentDetails(
val parent_id: Int = 0,
val parent_name: String = "",
val parent_email: String = "",
val parent_relation: String = "",
val parent_location: String = ""
)
and then you execute
val new_parent = ParentDetails(0, "myName", "myEmail", "myParent_relation", "myLocationdata")
println(new_parent)
you will receive as result
ParentDetails(parent_id=0, parent_name=myName, parent_email=myEmail, parent_relation=myParent_relation, parent_location=myLocationdata)
This is because data classes override the toString() function:
The compiler automatically derives the following members from all
properties declared in the primary constructor:
equals()/hashCode() pair;
toString() of the form "User(name=John, age=42)";
Did you check that you receive valid data from your intent.extras?
Also I suggest you use data class for your models.
It will look something like this:
data class ParentDetails(
var parent_id: Int = 0,
var parent_name: String = "",
var parent_email: String = "",
var parent_relation: String = "",
var parent_location: String = ""
)
You will be able to use it like this :
val new_parent = ParentDetails(
parent_name = intent.extras.getString("name"),
parent_email = intent.extras.getString("email"),
parent_relation = intent.extras.getString("parent_relation"),
parent_location = intent.extras.getString("locationdata")
)
println(new_parent.tostring())
As already mentioned, you have a typo. toString returns the hashcode of an object unless it's overridden to return something else. Look up the original implementation for more details.
By overriding the toString method, you change what it returns, and through that, what is printed when you print(someClass). DVarga showed that in their answer.
Data classes auto-generate a toString method containing the content of the class. So creating a data class is a shortcut to getting output containing the data.
The reason the method you had didn't work is because you didn't call it. if you call it instead of toString, you would get the data printed.
Also, toString is explicitly called when you print a class. You don't need to call print(someInstance.toString()), print(someInstance) is enough.
And while I'm writing an answer, you don't need to use secondary constructors in Kotlin. Primary constructors would shorten your code significantly, whether it's a data class or not. Also, you should look into naming conventions.

PostSharp OnException. How can i get arguments for complex parameters

I wrote a OnMethodBoundaryAspect attribute for Logging the methods exceptions.
I am in trouble with Complex method parameter.
The method signature is:
TestClass m_tf = new TestClass();
m_tf.DoWorkInternal(1, new Prova1() { ProvaP1=10, ProvaP2=11 });
I be able to trace the first parameter of type int, so i can get the parameter name and value.
But how can i get the values of the properties of the second parameters that is a complex object ?
Thanks in advance.
Giuseppe.
RESOLVED.
Found solution.
The aspect method is like this, and write the target method parameters in json format:
public override void OnException(MethodExecutionArgs args)
{
base.OnException(args);
Dictionary<string, object> m_args = new Dictionary<string, object>();
for (int i = 0; i < args.Arguments.Count(); i++)
{
string name = args.Method.GetParameters()[i].Name;
object obj = args.Arguments.GetArgument(i);
m_args.Add(name, obj);
}
var output = JsonConvert.SerializeObject(m_args);
:
:
}
While you can turn the parameter/argument array into a dictionary and JSON serialize it, another way would be just find it directly using the type.
Following code should do the trick for you.
public override void OnException(MethodExecutionArgs args)
{
Prova1 prova1 = null;
var parameters = args.Method.GetParameters();
var arguments = args.Arguments
for (int i = 0; i < arguments.Count(); i++)
{
var param = parameters[i];
var arg = arguments[i];
if (param.ParameterType == typeof(Prova1))
{
prova1 = arg;
}
}
var output = prova1;
// Do your magic
base.OnException(args);
}
Also, keep in mind of two things.
System.Linq functions should be able to clean out that function a lot.
You are looping through the argument list every time there is an exception. However, the indices of your parameters never change. Thus, you should be able to calculate the index of the complex method parameter once (either in CompileTimeInitialize() or RuntimeInitialize()) and re-use that index.

Postsharp introduce Attributes with Property Arguments

I am trying to achieve attribute introduction like here but my attributes have property arguments like: [Foo(Bar = "Baz")]
How do I correctly pass the arguments? I'm not copying the attributes from something else, so I don't think I can use CustomAttributeData?
You can set properties of your custom attributes by using ObjectConstruction.NamedArguments dictionary.
For example:
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type targetType = (Type) targetElement;
var objectConstruction =
new ObjectConstruction(typeof (MyCustomAttribute).GetConstructor(Type.EmptyTypes));
objectConstruction.NamedArguments["Bar"] = "Baz";
var introduceAttributeAspect = new CustomAttributeIntroductionAspect(objectConstruction);
yield return new AspectInstance(targetType, introduceAttributeAspect);
}

How to observe a collection of items for when they are all valid?

I'm using ReactiveUI and the provided ReactiveCollection<> class.
In a ViewModel I have a collection of objects, and I wish to create an observable that watches those items for their IsValid property.
This is the scenario I'm trying to solve. In my ViewModel's constructor.
this.Items = new ReactiveCollection<object>();
IObservable<bool> someObservable = // ... how do I watch Items so when
// any items IsValid property changes,
// this observable changes. There
// is an IValidItem interface.
this.TheCommand = new ReactiveCommand(someObservable);
...
interface IValidItem { bool IsValid { get; } }
EDIT Ana's answer got me most of the way there. The solution is the following.
this.Items = new ReactiveCollection<object>();
this.Items.ChangeTrackingEnabled = true;
var someObservable = this.Items.Changed
.Select(_ => this.Items.All(i => i.IsValid));
It depends on what you want to do with the results of IsValid. Here's how I would do it, though it's not entirely intuitive:
// Create a derived collection which are all the IsValid properties. We don't
// really care which ones are valid, rather that they're *all* valid
var isValidList = allOfTheItems.CreateDerivedCollection(x => x.IsValid);
// Whenever the collection changes in any way, check the array to see if all of
// the items are valid. We could probably do this more efficiently but it gets
// Tricky™
IObservable<bool> areAllItemsValid = isValidList.Changed.Select(_ => isValidList.All());
theCommand = new ReactiveCommand(areAllItemsValid);
Since you are using ReactiveUI, you have a few options. If your objects are ReactiveValidatedObjects you can actually use the ValidationObservable:
var someObservable = this.Items
.Select(o => o.ValidationObservable
.Select(chg => chg.GetValue()) //grab just the current bool from the change
.StartsWith(o.IsValid)) //prime all observables with current value
.CombineLatest(values => values.All());
If they aren't ReactiveValidatedObjects, but implement INotifyPropertyChanged, you would just replace the first line and use the handy ObservableForProperty extension method in ReactiveUI for those objects. Instead of o.ValidationObservable you would use o.ObservableForProperty(x => x.IsValid). The rest should be the same.
This is a pretty common use case and I've wrapped it in an extension method for IEnumerable<ReactiveValidatedObject>
I'm sure Paul Betts will come along with something more elegant, but this is what I do.

Can't use string.Format() in Anonymous Type

I'm hoping to achieve something as follows:
var comboBoxItems = from state in states
select new
{
Key = state.Code,
Value = string.Format("{0} ({1})", state.Name, state.Code)
};
this.stateComboBox.DisplayMember = "Value";
this.stateComboBox.ValueMember = "Key";
this.stateComboBox.DataSource = new BindingSource(comboBoxItems, null);
However, it gives me the following error when it attempts to bind to the DataSource:
"LINQ to Entities does not recognize the method 'System.String
Format(System.String, System.Object, System.Object)' method, and this
method cannot be translated into a store expression."
Is there any way to include a method like string.Format() in the Anonymous Type?
var comboBoxItems = from state in states.ToList()
select new
{
Key = state.Code,
Value = string.Format("{0} ({1})", state.Name, state.Code)
};
You cannot use Format in LINQ 2 Entities as it cannot be translated to SQL. A call to ToList will cause the items to be loaded from DB and your format will now execute properly.