Return all the fields from a class - c#

I am attempting to cycle through the Fields in my class, place the fields of a certain type into a list and then return that list. I know I am missing some key component but I cannot figure out what I am doing wrong. This is what I have so far:
...
I need to return a list of the actual fields as pointers, not a copy of the data. Any help in getting this to work would be appreciated.
I removed the above code (you should still be able to see it in the history) because it was confusing. This is the updated code (with some extra stuff removed) that works thanks to the answer from competent_tech:
string prop1;
BaseClass prop2;
SubClass prop3;
SubClass prop4;
public List<BaseClass> GetData()
{
List<BaseClass> DataList = new List<BaseClass>();
foreach (System.Reflection.PropertyInfo thisInfo in this.GetType().GetProperties())
{
var tempPropery = thisInfo.GetValue(this, null);
if (tempPropery.GetType().IsSubclassOf(typeof(BaseClass)) || tempPropery.GetType().Equals(typeof(BaseClass)))
{
DataList.Add((BaseClass)tempPropery);
};
}
return DataList;
}
The above code will allow you to get all the properties of a specific base type from your class and return them in a list. So the above code would return prop2 - prop4.

You can accomplish this through reflection.
foreach (System.Reflection.PropertyInfo oProperty in this.GetType().GetProperties()) {
}
There are numerous ways that you can use this information once you have it or filter the properties (for example, by adding an attribute to the properties that you want to collect).
You can get more information from MSDN.
Note that this code specifically references properties, but there are equivalent methods for retrieving fields (GetFields) and all members (GetMembers).
Once you have the PropertyInfo, you can call the GetValue method:
foreach (System.Reflection.PropertyInfo oProperty in this.GetType().GetProperties()) {
Console.WriteLine(oProperty.Name + " = " + oProperty.GetValue(this, null).ToString());
}
Alternatively, if you are looking at both fields and properties:
foreach (System.Reflection.MemberInfo oMember in this.GetType().GetMembers())
{
switch (oMember.MemberType)
{
case System.Reflection.MemberTypes.Field:
var oField = (System.Reflection.FieldInfo)oMember;
Console.WriteLine(oField.Name + " = " + oField.GetValue(this).ToString());
break;
case System.Reflection.MemberTypes.Property:
var oProperty = (System.Reflection.PropertyInfo)oMember;
Console.WriteLine(oProperty.Name + " = " + oProperty.GetValue(this, null).ToString());
break;
}
}

You can store data in Dictionary. For every property only set/get value from dictionary.
Something like this:
public class MyData {
private Dictionary<string, object> myData;
public MyData {
this.myData = new Dictionary<string, object>();
}
public decimal LastVersion { get { return (decimal)this.myData["LastVersion"]; } private set { this.myData["LastVersion"] = value; } }
public PrimaryAbility STR { get { return (PrimaryAbility)this.myData["STR"]; } private set { this.myData["STR"] = value; } }
public PrimaryAbility DEX { get { return (PrimaryAbility)this.myData["DEX"]; } private set { this.myData["DEX"] = value; } }
public PrimaryAbility CON { get { return (PrimaryAbility)this.myData["CON"]; } private set { this.myData["CON"] = value; } }
public PrimaryAbility INT { get { return (PrimaryAbility)this.myData["INT"]; } private set { this.myData["INT"] = value; } }
public PrimaryAbility WIS { get { return (PrimaryAbility)this.myData["WIS"]; } private set { this.myData["WIS"] = value; } }
public PrimaryAbility CHA { get { return (PrimaryAbility)this.myData["CHA"]; } private set { this.myData["CHA"] = value; } }
public DerivedAbility HP { get { return (DerivedAbility)this.myData["HP"]; } private set { this.myData["HP"] = value; } }
public DerivedAbility MP { get { return (DerivedAbility)this.myData["MP"]; } private set { this.myData["MP"] = value; } }
public DerivedAbility SP { get { return (DerivedAbility)this.myData["SP"]; } private set { this.myData["SP"] = value; } }
public DerivedAbility AC { get { return (DerivedAbility)this.myData["AC"]; } private set { this.myData["AC"] = value; } }
}
Some day I found this: "Enum.GetValues(typeof(TvStations))", maybe you should search some like this.

Related

C# Sorted list without LINQ and SORT

My question is that is it possible to create a list that sorts the objects in it upon these object being placed in them?
After not getting anywhere, I made a new linked list. The only task is to make this list ordered by the string field of the objects it will containt while remaining foreachable.
I have the following code:
class LancoltLista<T> : IEnumerable
{
class ListaElem
{
public T tartalom;
public ListaElem kovetkezo;
}
ListaElem fej;
public void ElejereBeszuras(T elem)
{
ListaElem uj = new ListaElem();
uj.tartalom = elem;
uj.kovetkezo = fej;
fej = uj;
}
public void VegereBeszuras(T elem)
{
if (fej == null)
{
ElejereBeszuras(elem);
}
else
{
ListaElem e = fej;
while (e.kovetkezo != null)
{
e = e.kovetkezo;
}
ListaElem uj = new ListaElem();
uj.tartalom = elem;
e.kovetkezo = uj;
}
}
public IEnumerator GetEnumerator()
{
return new ListaBejaro(fej);
}
class ListaBejaro : IEnumerator<T>
{
ListaElem elso, jelenlegi;
public ListaBejaro(ListaElem elso)
{
this.elso = elso;
jelenlegi = null;
}
public bool MoveNext()
{
if (jelenlegi == null)
{
jelenlegi = elso;
}
else
{
jelenlegi = jelenlegi.kovetkezo;
}
return jelenlegi != null;
}
public void Reset()
{
jelenlegi = null;
}
object IEnumerator.Current
{
get { return this.jelenlegi.tartalom; }
}
public T Current
{
get { return this.jelenlegi.tartalom; }
}
public void Dispose()
{
elso = null;
jelenlegi = null;
}
}
}
The problem here is that I'm not able to compare p.kulcs and kulcs.
For real world applications you could use the built-in SortedList<T>.
For your homework, you will have to check every item that you get in your add method against the entire list and insert it into the correct place: between the last element that it's grater than or equal to, and the first element that it's smaller then.
Of course, if the list is empty, or if there is no element greater than the one you add, then you simply append the element to the last available location.
Since this is homework, I'll leave you to write the code yourself.

Generic List is not being inserted into MongoDB

I'm trying to insert a protobuf-net object into my MongoDB. The object looks something like this:
message Measurement
{
optional string _someString1 = 1 [default = ""];
optional string _someString2 = 2 [default = ""];
repeated MyMessage1 _myMessages1 = 3;
repeated MyMessage2 _myMessages2 = 4;
repeated MyMessage3 _myMessages3 = 5;
}
MyMessage1..3 are messages in the same proto file and they contain a few strings, doubles and int64s.
I fill an instance of Measurement with some data and try to insert it into my DB, like this:
var col = MyDatabase.GetCollection<Measurement>("Measurements");
col.Insert(instanceOfMeasurement);
Now, if I check on the contents of the DB, I can see that the instanceOfMeasurement has been added correctly. But the repeated fields within haven't. Do I need to prepare a more complex object in some way, before stuffing it into MongoDB?
Okay, here is what protobuf-net creates:
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=#"Measurement")]
public partial class Measurement : global::ProtoBuf.IExtensible, global::System.ComponentModel.INotifyPropertyChanged
{
public Measurement() {}
private string __someString1;
[global::ProtoBuf.ProtoMember(1, IsRequired = false, Name=#"_someString1", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string _SomeString1
{
get { return __someString1?? ""; }
set { __someString1 = value; OnPropertyChanged(#"_someString1"); }
}
[global::System.Xml.Serialization.XmlIgnore]
[global::System.ComponentModel.Browsable(false)]
public bool _someString1Specified
{
get { return this.__someString1 != null; }
set { if (value == (this.__someString1== null)) this.__someString1 = value ? this._someString1 : (string)null; }
}
private bool ShouldSerialize_someString1() { return _someString1Specified; }
private void Reset_someString1() { _someString1Specified = false; }
private string __someString2;
[global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=#"_someString2", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string _SomeString2
{
get { return __someString2?? ""; }
set { __someString2 = value; OnPropertyChanged(#"_someString2"); }
}
[global::System.Xml.Serialization.XmlIgnore]
[global::System.ComponentModel.Browsable(false)]
public bool _someString2Specified
{
get { return this.__someString2 != null; }
set { if (value == (this.__someString2== null)) this.__someString2 = value ? this._someString2 : (string)null; }
}
private bool ShouldSerialize_someString2() { return _someString2Specified; }
private void Reset_someString2() { _someString2Specified = false; }
private readonly global::System.Collections.Generic.List<MyMessage1> __myMessages1 = new global::System.Collections.Generic.List<MyMessage1>();
[global::ProtoBuf.ProtoMember(6, Name=#"_myMessages1", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<MyMessage1> _myMessages1
{
get { return __myMessages1; }
}
private readonly global::System.Collections.Generic.List<MyMessage2> __myMessages2 = new global::System.Collections.Generic.List<MyMessage2>();
[global::ProtoBuf.ProtoMember(7, Name=#"_myMessages2", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<MyMessage2> _myMessages2
{
get { return __myMessages2; }
}
private readonly global::System.Collections.Generic.List<MyMessage3> __myMessages3 = new global::System.Collections.Generic.List<MyMessage3>();
[global::ProtoBuf.ProtoMember(8, Name=#"_myMessages3", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<MyMessage3> _myMessages3
{
get { return __myMessages3; }
}
public event global::System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{ if(PropertyChanged != null) PropertyChanged(this, new global::System.ComponentModel.PropertyChangedEventArgs(propertyName)); }
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
}
The driver doesn't by default serialize properties that have no setter. Evidently that includes the messages on Measurement.
To override the default behavior and include these properties* you either mark them with the BsonElement attribute or map them with RegisterClassMap. In this case where the classes are auto-generated an attribute would be a bad idea so use the latter:
BsonClassMap.RegisterClassMap<Measurement>(m =>
{
m.MapProperty(x => x.MyMessage1);
m.MapProperty(x => x.MyMessage2);
m.MapProperty(x => x.MyMessage3);
});
More in Serialize Documents with the C# Driver: Opt In
* When a readonly property is serialized, it value is persisted to the database, but never read back out. This is useful for storing “computed” properties

.NET bind checked property of checkbox with SqlByte datatype

This fails:
dtaAutomaticFlag.DataBindings.Add("Checked", BndSource, "AutomaticFlag");
most probably because AutomaticFlag is defined as:
public SqlByte AutomaticFlag { get; set; }
SQL Server is tinyint. The reason is that i dont only need 0 and 0 as values.
I need to be checked if the value is 1 , unchecked for ALL other values.
One thing that i thought is to create an extra property AutomaticFlagBoolean in my class and check the AutomaticFlag and bind to the new property.
This is what i tried but i get always false:
private SqlByte _automaticFlag;
public SqlByte AutomaticFlag
{
get { return _automaticFlag; }
set
{
if (_automaticFlagBoolean)
{
_automaticFlag = 1;
}
else
{
_automaticFlag = 0;
}
}
}
private bool _automaticFlagBoolean;
public bool AutomaticFlagBoolean
{
get
{
if (_automaticFlag == 1)
{
return _automaticFlagBoolean = true;
}
else
{
return _automaticFlagBoolean = false;
}
}
set { _automaticFlagBoolean = value; }
}
this is in my binding:
dtaAutomaticFlag.DataBindings.Add("Checked", BndSource, "AutomaticFlagBoolean");
The checkbox control expects a boolean value for binding.
Try using a local variable to hold the value:
private SqlByte _automaticFlag;
private bool _automaticFlagBoolean;
public SqlByte AutomaticFlag
{
get { return _automaticFlag; }
set
{
_automaticFlag = value;
_automaticFlagBoolean = (_automaticFlag != 0);
}
}
public bool AutomaticFlagBoolean
{
get
{
return _AutomaticFlagBookean;
}
set { _automaticFlagBoolean = value;
if (_automaticFlagBoolean) {
_automaticFlag = 1;
} else {
_automaticFlag = 0;
}
}
}
Then bind as so:
dtaAutomaticFlag.DataBindings.Add("Checked", BndSource, "AutomaticFlagBoolean");
Your class should also implement INotifyPropertyChanged as well but that's a little beyond the scope of your question.

Dapper. Map to SQL Column with spaces in column names

I've managed to get something up and running today as small sandbox/POC project, but have seemed to bump my head on one issue...
Question:
Is there a way to get dapper to map to SQL column names with spaces in them.
I have something to this effect as my result set.
For example:
SELECT 001 AS [Col 1],
901 AS [Col 2],
00454345345345435349 AS [Col 3],
03453453453454353458 AS [Col 4]
FROM [Some Schema].[Some Table]
And my class would look like this
public class ClassA
{
public string Col1 { get; set; }
public string Col2 { get; set; }
///... etc
}
My implementation looks like this at the moment
public Tuple<IList<TClass>, IList<TClass2>> QueryMultiple<TClass, TClass2>(object parameters)
{
List<TClass> output1;
List<TClass2> output2;
using (var data = this.Connection.QueryMultiple(this.GlobalParameter.RpcProcedureName, parameters, CommandType.StoredProcedure))
{
output1 = data.Read<TClass>().ToList();
output2 = data.Read<TClass2>().ToList();
}
var result = new Tuple<IList<TClass>, IList<TClass2>>(output1, output2);
return result;
}
Note: The SQL cant be modified in any way.
Currently I'm going through the dapper code, and my only foreseeable solution is to add some code to "persuade" the column comparison, but not having much luck so far.
I've seen on StackOverflow that there are things like dapper extensions, but I'm hoping I can get this done without adding an extention, if not. I'll take whatever is quickest to implement.
There's a nuget package Dapper.FluentMap that allows you to add column name mappings (including spaces). It's similar to EntityFramework.
// Entity class.
public class Customer
{
public string Name { get; set; }
}
// Mapper class.
public class CustomerMapper : EntityMap<Customer>
{
public CustomerMapper()
{
Map(p => p.Name).ToColumn("Customer Name");
}
}
// Initialise like so -
FluentMapper.Initialize(a => a.AddMap(new CustomerMapper()));
see https://github.com/henkmollema/Dapper-FluentMap for more.
One option here would be to go via the dynamic / non-generic API, and then fetch the values out via the IDictionary<string,object> API per row, but that might be a bit tedious.
As an alternative, you can create a custom mapper, and tell dapper about it; for example:
SqlMapper.SetTypeMap(typeof(ClassA), new RemoveSpacesMap());
with:
class RemoveSpacesMap : Dapper.SqlMapper.ITypeMap
{
System.Reflection.ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(System.Reflection.ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
var prop = typeof(ClassA).GetProperty(columnName.Replace(" ", ""));
return prop == null ? null : new PropertyMemberMap(columnName, prop);
}
class PropertyMemberMap : Dapper.SqlMapper.IMemberMap
{
private string columnName;
private PropertyInfo property;
public PropertyMemberMap(string columnName, PropertyInfo property)
{
this.columnName = columnName;
this.property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
System.Reflection.FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return property.PropertyType; }
}
System.Reflection.ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
System.Reflection.PropertyInfo SqlMapper.IMemberMap.Property
{
get { return property; }
}
}
}
I had a similar problem when trying to get mapped results from a call to the system sp_spaceused procedure. Marc's code didn't quite work for me as it complained about not being able to find a default constructor. I also made my version generic so it could theoretically be re-used. This may not be the fastest performing piece of code, but it works for me and in our situation these calls are made infrequently.
class TitleCaseMap<T> : SqlMapper.ITypeMap where T: new()
{
ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return typeof(T).GetConstructor(Type.EmptyTypes);
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
string reformattedColumnName = string.Empty;
foreach (string word in columnName.Replace("_", " ").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
reformattedColumnName += char.ToUpper(word[0]) + word.Substring(1).ToLower();
}
var prop = typeof(T).GetProperty(reformattedColumnName);
return prop == null ? null : new PropertyMemberMap(prop);
}
class PropertyMemberMap : SqlMapper.IMemberMap
{
private readonly PropertyInfo _property;
public PropertyMemberMap(PropertyInfo property)
{
_property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return _property.PropertyType; }
}
ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
PropertyInfo SqlMapper.IMemberMap.Property
{
get { return _property; }
}
}
}
I know this is an old question nevertheless i faced the same problem in my last project, so i just created an own mapper using attributes.
I defined an attribute class called ColumnNameAttribute.cs
using System;
namespace DapperHelper.Attributes
{
[System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
sealed class ColumNameAttribute : Attribute
{
private string _columName;
public string ColumnName
{
get { return _columName; }
set { _columName = value; }
}
public ColumNameAttribute(string columnName)
{
_columName = columnName;
}
}
}
After defining the attribute, i implemeted a dynamic mapper that uses the Query method from Dapper but works as the Query<T>:
using Dapper;
using DapperHelper.Attributes;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Web.Routing;
namespace DapperHelper.Tools
{
public class DynamicMapper<T> :IDisposable where T : class, new()
{
private readonly Dictionary<string, PropertyInfo> _propertiesMap;
public DynamicMapper()
{
_propertiesMap = new Dictionary<string, PropertyInfo>();
PropertyInfo[] propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (propertyInfo.GetCustomAttribute(typeof(ColumNameAttribute)) is ColumNameAttribute columNameAttribute)
{
_propertiesMap.Add(columNameAttribute.ColumnName, propertyInfo);
}
else
{
_propertiesMap.Add(propertyInfo.Name, propertyInfo);
}
}
}
public List<T> QueryDynamic(IDbConnection dbConnection, string sqlQuery)
{
List<dynamic> results = dbConnection.Query(sqlQuery).ToList();
List<T> output = new List<T>();
foreach (dynamic dynObj in results)
{
output.Add(AssignPropertyValues(dynObj));
}
return output;
}
private T AssignPropertyValues(dynamic dynamicObject)
{
T output = new T();
RouteValueDictionary dynamicObjProps = new RouteValueDictionary(dynamicObject);
foreach (var propName in dynamicObjProps.Keys)
{
if (_propertiesMap.TryGetValue(propName, out PropertyInfo propertyMapped)
&& dynamicObjProps.TryGetValue(propName, out object value))
{
propertyMapped.SetValue(output, value);
}
}
return output;
}
public void Dispose()
{
_propertiesMap.Clear();
}
}
}
To use it, you have to refer to your Model class and define the attribute:
using DapperHelper.Attributes;
namespace Testing
{
public class Sample
{
public int SomeColumnData { get; set; }
[ColumnName("Your Column Name")]
public string SpecialColumn{ get; set; }
}
}
and then you can implement something like this:
DynamicMapper<Sample> mapper = new DynamicMapper<Sample>();
List<Sample> samples = mapper.QueryDynamic(connection, "SELECT * FROM Samples");
I hope it can help someone looking for an alternative.

how i can show object in gridview or in any usful contro

public class EventDetail
{
private Int64 logID;
public Int64 LogID
{
get { return logID; }
set { logID = value; }
}
private Object logedObject;
public Object LogedObject
{
get { return logedObject; }
set { logedObject = value; }
}
}
First off, you dont need to use fields if you do nothing in the property other then set it.
public Object LogedObject { get; set; }
is enough.
Secondly, to show a list of your objects in a DataGrid, as example.
protected void Page_Load(object sender, EventArgs e)
{
DataGrid dg = new DataGrid();
dg.DataSource = getModels();
dg.DataBind();
}
public List<EventDetail> getModels()
{
var m = new List<EventDetail>();
for (int a = 0; a < 15; a++)
{
m.Add(new EventDetail() { prop1 = a, prop2 = string.Format("Prop2 {0}", a) });
}
return m;
}
public class EventDetail
{
public Int64 LogID { get; set; }
public Object LogedObject { get; set; }
}
Look at the DataBinder class, it should allow you to do what you want ;-)
To bind with GridView (or similar controls such as Repeater, ListView), you typically need to know property names of object because that's what you will use to bind column to. So is this example, you may bind to LogID and LogedObject properties. For later, ToString will be invoked on object to show the string representation.
Instead of returning collection of class EventDetail, if you only have to bind logedevent, then do the following. Extract the collection of LogedObject in some other collection or
directly bind it to grid
protected void BindGrid()
{
gv.DataSource = EventDetail_Object.LogedObect_Property_Of_Class;
gv.DataBind();
}
tanx for any body help me
i solve this problem by reflection
i use refelection to get my properties of my object an thie values an then add this value to my string list
//exteract properties of loged object
PropertyInfo[] _PropertyInfo = _ObjectType.GetProperties();
List<string> _ObjBeforTostring = new List<string>();
//_ObjBeforTostring.Add("");
_ObjBeforTostring.Add("*************Befor Object**********");
_ObjBeforTostring.Add("");
foreach (PropertyInfo pf in _PropertyInfo)
{
if (_objbefor != null)
{
string _str = pf.GetValue(_objbefor, null).ToString();
_ObjBeforTostring.Add(pf.Name.ToString() + " :: ( " + _str + " )");
_ObjBeforTostring.Add("==============================");
}
}
_ObjBeforTostring.Add("");
_ObjBeforTostring.Add("*************After Object**********");
_ObjBeforTostring.Add("");
foreach (PropertyInfo pf in _PropertyInfo)
{
if (_objAfter != null)
{
string _str = pf.GetValue(_objAfter, null).ToString();
_ObjBeforTostring.Add(pf.Name.ToString() + " :: ( " + _str+" )");
_ObjBeforTostring.Add("==============================");
}
}

Categories

Resources