I was wondering if it was possible to referance a class field via variable. like so:
int variable = 0;
while (variable > 3)
{
class._fieldvariable = something;
i++
}
where if I have fields: _field1, _field2, _field3 I can iterate through them all.
The main reason for doing this is I have an sql query that will append multiple records and I'd rather not have to do all the parameters multiple times but rather something like this:
while (i < 4)
}
command.Parameters.AddWithValue("#Alpha1", _alphai01.ToString());
i++
}
to let me set parameters 3 times with _alpha101, _alpha201 and _alpha301 are used for three different queries.
thanks!
Associate properties to the fields, all of them with get/set access.
If we're really talking about three fields, a more or less clean way to do so is by using a function GetField(int index) which would return the corresponding property. Then your code can be
class.GetField(i) = something;
An array is better in the more general case (for example, if the number of fields is expected to change).
I would prefer not to use reflection for such a simple purpose.
You can use invokeMember to call a certain setter of a property:
Object obj; //your instance;
obj.GetType().InvokeMember("Alpha1",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, "ValueForAlpha1");
that's equal to
obj.Alpha1 = "ValueForAlpha1";
http://msdn.microsoft.com/en-US/library/vstudio/66btctbe.aspx
You could use reflection like this
if you have a class A
public class A
{
int field1, field2, field3;
}
you could set these fields like this
A obj = new A();
for (int i = 1; i < 4; i++)
{
FieldInfo field = obj.GetType().GetField(String.Format("field{0}", i), BindingFlags.NonPublic | BindingFlags.Instance);
if (null != field)
{
field.SetValue(obj, i);
}
}
Related
I would like to assign values to various classes. How I would achieve the code below would work?
T row = new T();
row[propertyName1] = "value 1";
row[propertyName2] = "value 2";
row[propertyName3] = "value 3";
I have various classes. I have property names for each class with values.
What I am trying to do is to assign all table values from database to classes Lists. All classes in C# are exact match to tables in SQL. Entitiy framework do this. I would like to build the same functionality as EF do.
You can use such thing using reflexion:
using System.Reflection;
static void Test()
{
var list = new List<int>();
list.SetProperty("Capacity", 10);
}
static BindingFlags DefaultBindingFlags
= BindingFlags.Public
| BindingFlags.Static
| BindingFlags.Instance;
static void SetProperty<T>(this T instance, string name, object value)
//where T : ...
{
PropertyInfo p = instance.GetType().GetProperty("Capacity", DefaultBindingFlags);
if ( p != null )
p.SetValue(instance, value, null);
else
throw new Exception($"Property {name} doesn't exist.");
}
I have a class which I'm trying to run a deep copy on. One of the members of this class is 'MeshContainers' which is an instance of MeshContainerCollection.
MeshContainerCollection<> inherits from my SceneObjectCollection<> class which inherits from List<>
What I noticed is that the source object has 1 item inside the meshcontainercollection while the cloned object has 0.
When stepping through the DeepCopy process I noticed that when I try to get the fields for MeshContainerCollection, it doesn't find any.
Now MeshContainerCollection doens't have any direct fields (only inherited fields) so I thought that was the problem.
But I use:
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
Which (afaik) should also return the private inherited members.
I have looked through the existing BindingFlags but haven't been able to figure out if there is another BindingFlag I should use to get the inherited private fields.
Could someone tell me how I can manage to do a REAL deep copy?
Deep Copy method I'm using:
private static object Process(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
else if (type.IsArray)
{
Type elementType = Type.GetType(
type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(Process(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = FormatterServices.GetUninitializedObject(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, Process(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
EDIT1: I prefer not to do this by serialization but by reflection.
As mentioned in GetFields documentation,
private fields on base classes are not returned.
Try this method instead:
public static IEnumerable<FieldInfo> GetAllFields(this Type type)
{
IEnumerable<FieldInfo> fields = type.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (type.BaseType == null)
return fields;
else
return GetAllFields(baseType).Concat(fields);
}
(you might want to rewrite it to avoid all the enumerables and concatenations, but you get the idea)
one of the ways that you could achieve this is by serializing the object and then deserializing it back.. write a function to do the same..
FYI, your class needs to be marked [Serializable] for this..
there are some libraries out there that do the same.. Copyable is one of them.. I would suggest not to try and reinvent the wheel rather build up on this library as there are too many edge conditions to handle when you deep copy.. may be you can submit patches to the author too..
I have a class:
class A {
public string a = "A-val" , b = "B-val";
}
I want to print the object members by reflection
//Object here is necessary.
Object data = new A();
FieldInfo[] fields = data.GetType().GetFields();
String str = "";
foreach(FieldInfo f in fields){
str += f.Name + " = " + f.GetValue(data) + "\r\n";
}
Here is the desired result:
a = A-val
b = B-val
Unfortunately this did not work. Please help, thanks.
Once fixed to get rid of the errors (lacking a semi-colon and a bad variable name), the code you've posted does work - I've just tried it and it showed the names and values with no problems.
My guess is that in reality, you're trying to use fields which aren't public. This code:
FieldInfo[] fields = data.GetType().GetFields();
... will only get public fields. You would normally need to specify that you also want non-public fields:
FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
(I hope you don't really have public fields, after all...)
Remember when you write fields like :
public string VarName{ get; set;}
Then actually you have this code(this is what reflection see) :
private string _varName;
public string get_VarName(){
....
}
public void set_VarName(strig value){
....
}
As #Stanislav say, you must keep in mind the backing fields generated by the compiler for properties. If you want to exclude these fields you can use the following code:
FieldInfo[] fields = data.GetType()
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
.ToArray();
I have 1 dto, statEMailDTO, which has a field that holds the Field Names of what I'm looking for (they are comma delimited.
var emailParams = statEmailDTO.EmailParam.ToString().Split(',');
for (int i = 0; i < emailParams.Length; i++) {
var fieldName = emailParams[i].ToString();
etc.
But, then how do I use Reflection to then get the Actual value of ``fieldName which is found in a different DTO, siDTO.
So let's say that fieldName = "SuggestionItemID", I then what to get the value of siDTO.SuggestionItemID.
I haven't done a lot of reflection in the past. Sure, I read up on PropertyInfo, but it's just not clicking.
Thoughts?
Like this:
PropertyInfo property = typeof(SomeType).GetProperty(fieldName);
object value = property.GetValue(instance, null);
I'm working with an existing object framework that uses special values to represent NULL for primitives int, DateTime, long. Data containing these values are added to a DataTable and displayed in third-party controls such as XtraGrid.
All is fine, except when aggregates are applied to the data. In this case, obviously the special values are processed instead of the NULL entries.
So I think the best solution is to map the values to/from DBNull when putting into the DataRow. I thought about subclassing the DataTable and DataRow, but the base classes don't allow overriding of the accessors.
I could add extra Get/Set functions to the subclasses but this relies on remembering to use them. I could add static helper functions instead of subclassing, but this has the same problem.
Is there a more elegant solution?
Update
It's the grid itself that is doing the aggregation, as it has flexible controls to let the user define summaries at run-time. So I think the only real solution is to map to/from DBNull somehow, just looking for an elegant way of doing this.
You may create an extension method to help you fill the datatable and convert values to dbnull:
public static class DataExtensions
{
public static DataRow AddRow(this DataRowCollection rowCollection, params object[] values)
{
object[] newValues = new object[values.Length];
for(int i=0;i<values.Length;i++)
{
object value = values[i];
if (value != null)
{
Type t = value.GetType();
//check for min value only for value types...
if (t.IsValueType)
{
//maybe you can do some caching for that...
FieldInfo info = t.GetField("MinValue",
System.Reflection.BindingFlags.Static
| System.Reflection.BindingFlags.Public
);
if (info != null)
{
object o = info.GetValue(null);
if (value.Equals(o)) //very important == will return false
{
value = DBNull.Value;
}
}
}
}
newValues[i] = value;
}
return rowCollection.Add(newValues);
}
}
And then you will be able to write something like:
t.Rows.AddRow(a,b,c,d,e);
maybe you can create conditional aggregates with IIF like (silly example):
DataTable t= new DataTable();
t.Columns.Add("id");
t.Columns.Add("id2");
t.Columns.Add("id3", typeof(int), "IIF(id="+int.MinValue.ToString()+",id2,id+id2)");
for (int i = 0; i < 5; i++)
{
t.Rows.Add(new object[] { i, 2 * i });
}
t.Rows.Add(new object[] { int.MinValue, 2000});
Edit: adapted to your comment on other post.