Am a beginner in C# language
I have a class like
public class Plan
{
int a;
int b;
int c;
}
Can in any way I get the nth property of the class.
for eg: planObject.propertyIndex
This would be of great help for my project, as I am getting index number denoting the property whose value is to be changed. What I am doing right now is using if...else .
if(index ==1)
{
planObject.a = 100;
}
else if(index ==2)
{
planObject.b = 100;
}
Is there any other solution for this by using reflection?
You could use reflection, however, i would strongly advise against. Instead use a collection like List<int> or int[]. In this case, since you want to get the nth int value, you could also use a Dictionary<int, int>:
public class Plan
{
Dictionary<int, int> Values;
public Plan()
{
Values = new Dictionary<int, int>();
Values.Add(1, 100);
Values.Add(2, 200);
Values.Add(3, 300);
}
// ...
}
Now you can access the value by the number:
int value = Values[1]; // 100
Here's a list version:
public class Plan
{
List<int> Values = new List<int>();
public Plan()
{
Values.Add(100);
Values.Add(200);
Values.Add(300);
}
// ...
}
You access it via (zero based) index:
int value = Values[0]; // 100
A word of WARNING, this is in no way for beginners at all. And it might just make the code more complex. This answer takes for granted that you have a working knowledge of extension methods and reflection.
public static class PlanExtension
{
PropertyInfo _info = typeof(Plan).GetProperties();
public static void SetValue(this Plan plan, int index, int value)
{
var prop = _info[index - 1]; // So 1 maps to 0.. or 1 in this case
prop.SetValue(plan, value, null);
}
public static int GetValue(this Plan plan, int index)
{
var prop = _info[index - 1]; // Mapping magic
return (int) prop.GetValue(plan, null);
}
}
Called like this:
var p = new Plan();
p.SetValue(1, 139); // "a"
var b = p.GetValue(2); // "b"
It would help if you had a definable order to the properties, like name or something. Also, error handling is a must when it comes to reflection.
There's no "property by index" feature, but one approach that would make consumption easier would be to build an indexer on the class and encapsulate the switch statement there. Maybe something like this:
public class Plan
{
public int this[int index]
{
get
{
switch (index)
{
case 1:
return this.a;
...
}
}
set
{
switch (index)
{
case 1:
this.a = value;
...
}
}
}
}
So, now using it looks like this:
planObject[i] = 100;
Now, in your case it looks like you have an additional need because you have a key (the index) and a value (e.g. 100), so you need to store your keys and values in a Dictionary. So, in your class that uses Plan create a private field:
private Dictionary<int, int> _values = new Dictionary<int, int>
{
{ 1, 100 },
{ 2, 200 },
...
}
To use the dictionary you'd do something like this:
planObject[i] = _values[i];
UPDATE: if you can't change the class Plan then you'll need to do something like this. First you need a map from index to property name:
private Dictionary<int, string> _properties = new Dictionary<int, string>
{
{ 1, "a" },
{ 2, "b" },
...
}
and next you'll need to set that property:
var t = planObject.GetType();
var p = t.GetProperty(_properties[i]);
if (p != null)
{
p.SetValue(planObject, 100);
}
If you must use the object, instead of suggested Collections.
Plan b = new Plan();
Type t = new Type(b.GetType());
var properties = t.GetProperties();
for(int index = 0; index < properties.Length; index++)
{
properties[index].SetValue(b, 100);
}
Instead of using loop, you can pass your own index in properties array.
I hope it helps.
Here is what you want
public class Foo
{
public int A {get;set;}
public string B {get;set;}
public object GetPropertyValueAt(int index)
{
var prop = this.GetType().GetProperties()[index];
return prop.GetValue(this, null);
}
}
Usage
Foo foo = new Foo() {A = 1, B = "abc"};
int valueA = (int)foo.GetPropertyValueAt(0);
string valueB = (string)foo.GetPropertyValueAt(1);
int valueUnknown = (int)foo.GetPropertyValueAt(2); //<--- this line will give you an exception.
Related
This question already has answers here:
How do I cast int to enum in C#?
(32 answers)
Closed 5 years ago.
namespace ChemicalTest
{
enum Echemicals { oxygen, hydrogen, carbon }
public class Chemicals
{
int[] chemicals = new int[3];
public Chemicals()
{
foreach (int i in chemicals)
{
int[i] = //How can I reference each enumeration here?
//For example (pseudocode) - (i)Echemicals
}
}
}
}
I have three enum values: oxygen {0}, hydrogen{1}, carbon{2}
I'd like to put each of these enums into an array to later be referenced by their own number, so that I could call them from the array.
I can use (int)Echemicals.hydrogen to return the default value of the second enumeration {1} but I don't know how to do this in reverse.
I am trying to store each of the names of the chemicals in an array by calling them by their integer value.
You just need to cast to your enum:
Echemicals val = (Echemicals)i;
But you don't need to use int[] for this. Maybe you should give more details as to what the issue is.
I believe it is easier if you do it the other way around, first get all enums and than cast them to integer:
var enumValues = Enum.GetValues(typeof(Echemicals));
var decimals = enumValues.OfType<Echemicals>().Select(x => (int)x).ToArray();
You can do something like this:
enum Echemicals {
oxygen = 1,
hydrogen = 2,
carbon = 3
}
// ...
int oxigenInt = (int) Echemicals.oxygen;
Echemicals oxigenEnum = (Echemicals) 1;
Alternatively you can use the Immutable Object Design:
public class Echemicals {
private int index;
private Echemicals(int index) {
this.index = index;
}
public static Echemicals _Oxygen = new Echemicals(1);
public static Echemicals Oxygen { get { return _Oxygen; } }
// Other elements
// A list of all values:
public static Echemicals[] _Values;
public static Echemicals[] Values { get { return _Values; } }
static Echemicals() {
_Values = new[] {Oxygen, /*other elements*/};
}
static Echemicals GetByIndex(index) {
return Values.FirstOrDefault(e => e.index == index);
}
}
A lot more work, but useful if you need more properties in that element other than just the index.
let's say i have list with properties like this:
Type ArrayType
String Value
i've got another list like this:
ArrayType=System.Int32
Value=44
Index=0
ArrayType=System.Int32
Value=11
Index=3
ArrayType=System.Int32
Value=7
Index=2
ArrayType=System.Int32
Value=5
Index=1
All values are in string !
I don't know what type will be it, int32 is only example. there will also be floats, strings, etc.
so... i'm creating new array of type which i readed from "ArrayType" property
dynamic newArray = Array.CreateInstance(typeOfArray, arraySize);
I know arraySize of coure
and the Arrays are created properly.
But now i want to copy all values (which are in string) to my new array:
but i have no idea how to cast it. i've tried something like this:
newArray.SetValue(element.Property.Value,element.Index);
it throw an exception that he can't write OBJECT to my array of ints
so then i've tried to cast in somehow:
newArray[element.Index] = Convert.ChangeType(element.Property.Value,element.Property.Type);
but it still can't cast the object
can someone help :) ?
I just made this code example:
var types = new[] { typeof(int), typeof(float), typeof(double) };
var elements = Enumerable.Range(1, 100)
.Select((value, index) => new Element(types[index % types.Length], value.ToString(), index));
var integers = elements.Where(element => element.ArrayType == typeof(int));
var array = Array.CreateInstance(typeof(int), 100);
Console.WriteLine(array.GetType());
foreach(var element in integers)
{
var value = Convert.ChangeType(element.Value, element.ArrayType);
array.SetValue(value, element.Index);
}
foreach(var value in array)
{
Console.WriteLine(value + " " + value.GetType());
}
Element class:
public class Element
{
public Type ArrayType { get; private set; }
public string Value { get; private set; }
public int Index { get; private set; }
public Element(Type type, string value, int index)
{
ArrayType = type;
Value = value;
Index = index;
}
}
Which just works
Ok, now all works :D thanks for help!
foreach (var element in groupedElement)
{
var newInstance = Activator.CreateInstance(element.Property.Type);
newInstance = element.Property.Value;
newArray.SetValue(Convert.ChangeType(newInstance, element.Property.Type, CultureInfo.InvariantCulture), element.Index);
}
public static int[] Sort(int[] ints)
{
var dictionary = new IndexedDictionary<int, int>();
foreach (var i in ints)
{
dictionary.Add(i, i);
}
for (int i = 0; i <= ints.Length - 1; i++)
{
var indexValue = dictionary[i].Key;
dictionary[indexValue - 1].Value = indexValue;
}
return dictionary.Values();
}
Is it a bucket sort? I've seen a few bucket sorts and they look more complicated than this. Also please ignore the IndexedDictionary class - its a custom class to allow for getting values by index.
Edit: CompuChip - if you want to see the IndexedDictionary:
public class IndexedDictionary<T, TY>
{
public class DicObject<T, Y>
{
public T Key { get; set; }
public Y Value { get; set; }
}
private HashSet<DicObject<T, TY>> list = new HashSet<DicObject<T, TY>>();
public void Add(T o, TY u)
{
list.Add(new DicObject<T, TY>{Key = o, Value = u});
}
public DicObject<T, TY> this[int i] {
get{return list.ElementAt(i);}
}
public T[] Keys()
{
return list.Select(x => x.Key).ToArray();
}
public TY[] Values()
{
return list.Select(x => x.Value).ToArray();
}
}
Its not the crux at all.
That is a form of pigeon hole sorting, but it's limited to only being capable of sorting collections with unique values ranging from 1 and up without gaps. (If you for example try to sort the array {4,3,2} it will crash.)
So, for any collection that it works for, it does the same thing as:
public static int[] Sort(int[] ints) {
return Enumerable.Range(1, ints.Length).ToArray();
}
The IndexedDictionary is only a complicated and slow way to iterate through the items in an arbitrary order and put each value in place according to the same arbitrary order so that they end up being sorted. You can do the same thing much simpler and faster with a regular array:
public static int[] Sort(int[] ints) {
int[] result = new int[ints.Length];
foreach (int value in ints) {
result[value - 1] = value;
}
return result;
}
For an implementation that works with collections that doesn't have to have a lowest value of 1 and be continuous, you would create an array that spans from the lowest to the highest value and put the values in it, then collect them in order:
public static int[] Sort(int[] ints) {
int min = ints.Min();
int max = ints.Max();
int?[] pigeonHoles = new int?[max - min + 1];
foreach (int value in ints) {
pigeonHoles[value - min] = value;
}
int[] result = new int[ints.Length];
int index = 0;
foreach (int? value in pigeonHoles) {
if (value.HasValue) {
result[index++] = value.Value;
}
}
return result;
}
I'm not sure how we can ignore the IndexedDictionary as it seems to be the crux of your algorithm, but assuming it works like a standard dictionary I would think this is basically an insert sort - you put all your values into a dictionary which inserts it in the right place to keep its keys sorted and in the end you just extract all the values which are in the proper order by then. However, all the hard work is invisible because it is inside the Dictionary class.
A similar solution in terms of standard classes would be something like
public static IEnumerable<int> Sort(int[] ints)
{
var dictionary = new Dictionary<int, bool>();
foreach (var i in ints)
{
dictionary.Add(i, false);
}
return dictionary.Keys;
}
(although this does not deal with numbers occurring more than once).
This problem is easiest described with code:
class Program
{
static void Main(string[] args)
{
int index = 0;
var listOfExpressions = new List<ClassHoldingExpression>();
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index]));
index++;
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index]));
var dictClass = new ClassWithDict();
dictClass.Dict[0] = "Test 1";
dictClass.Dict[1] = "Test 2";
foreach (var expr in listOfExpressions)
Console.WriteLine((string)expr.Eval(dictClass));
}
}
public class ClassWithDict
{
public ClassWithDict()
{
Dict = new Dictionary<int, object>();
}
public Dictionary<int, object> Dict { get; set; }
}
public class ClassHoldingExpression
{
private Expression<Func<ClassWithDict, object>> Expression { get; set; }
public ClassHoldingExpression(Expression<Func<ClassWithDict, object>> expr)
{
Expression = expr;
}
public object Eval(ClassWithDict source)
{
return this.Expression.Compile().Invoke(source);
}
}
//Output:
//Test 2
//Test 2
//Desired:
//Test 1
//Test 2
Basically, I want to populate that dictionary with multiple values, and populate the list of ClassHoldingExpression with different expressions at specific indeces. However, it seems to look back and look for the current value of "index", instead of saving the current value into the expression. How can I force it to save the current value of index into the Expression?
You will have to create a new variable that will hold the value that you want.
int index0 = 0;
var listOfExpressions = new List<ClassHoldingExpression>();
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index0]));
int index1 = index0 + 1;
listOfExpressions.Add(new ClassHoldingExpression((a) => a.Dict[index1]));
If you need to do that in a loop, define a variable for each loop iteration before capturing it.
looks like a closure issue.
foreach (var TMPexpr in listOfExpressions){
var expr = TMPexpr ; // take LOCAL copy
Console.WriteLine((string)expr.Eval(dictClass));
}
similar SO post
I'm trying to get the value of a specified index of a property using reflection.
This answer works for standard properties that are of type List<> for example, but in my case, the collection I am trying to work with is of a different format:
public class NumberCollection : List<int>
{
public NumberCollection()
{
nums = new List<int>();
nums.Add(10);
}
public new int this[int i]
{
get { return (int) nums[i]; }
}
private List<int> nums;
}
public class TestClass
{
public NumberCollection Values { get; private set; }
public TestClass()
{
Values = new NumberCollection();
Values.Add(23);
}
}
class Program
{
static void Main(string[] args)
{
TestClass tc = new TestClass();
PropertyInfo pi1 = tc.GetType().GetProperty("Values");
Object collection = pi1.GetValue(tc, null);
// note that there's no checking here that the object really
// is a collection and thus really has the attribute
String indexerName = ((DefaultMemberAttribute)collection.GetType()
.GetCustomAttributes(typeof(DefaultMemberAttribute),
true)[0]).MemberName;
// Code will ERROR on the next line...
PropertyInfo pi2 = collection.GetType().GetProperty(indexerName);
Object value = pi2.GetValue(collection, new Object[] { 0 });
Console.Out.WriteLine("tc.Values[0]: " + value);
Console.In.ReadLine();
}
}
This code gives an AmbiguousMatchException ("Ambiguous match found."). I know my collection class is somewhat contrived, but can anyone help with this?
One option is to use
var prop = Type.GetProperties()
.Where(prop => prop.DeclaringType == collection.GetType())
.First();
Change Collection.GetType() to another type if you want. But basically: loop over the properties instead of using Type.GetProperty.
If you are looking for all of the default members, you can ask for Type.GetDefaultMembers(), then examine the members to find the one that you are looking for.
Alternatively, if you know the data type of the indexer, you can call GetPropertyInfo with the type array specifier.