For Some debug i need to get the list of SqlDataRecord generated by the method IEnumerator IEnumerable.GetEnumerator() of the class TVPDataCollection
this code :
TVPDataCollection<AttributiDocumento> oAttributiDocumentoList = new TVPDataCollection<AttributiDocumento>();
AttributiDocumento doc1 = new AttributiDocumento();
AttributiDocumento doc2 = new AttributiDocumento();
oAttributiDocumentoList.Add(doc1);
oAttributiDocumentoList.Add(doc2);
var x = oAttributiDocumentoList.GetEnumerator();
x is a list of AttributiDocumento, but i need a list of SqlDataRecord because i want to inspect the values. what's the way to call the GetEnumerator() that returns SqlDataRecord?
public class TVPDataCollection<T> : List<T>, IEnumerable<SqlDataRecord> where T : class
{
IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
{
List<SqlMetaData> records = new List<SqlMetaData>();
var properties = typeof(T).GetProperties();
foreach (var prop in properties)
{
SqlType oSqlType = GetSqlType(prop);
if (oSqlType.UseSize)
records.Add(new SqlMetaData(prop.Name, oSqlType.SqlDbType, oSqlType.Size));
else
records.Add(new SqlMetaData(prop.Name, oSqlType.SqlDbType));
}
SqlDataRecord oSqlDataRecord = new SqlDataRecord(records.ToArray());
foreach (T data in this)
{
for (int i = 0; i < properties.Length; i++)
{
oSqlDataRecord.SetValue(i, properties[i].GetValue(data, null));
}
yield return oSqlDataRecord;
}
}
}
public class AttributiDocumento
{
public int IdProvPart { get; set; }
//uso stringa in quanto con data agigunge 2 ore del fuso orario
public DateTime Data { get; set; }
public int Articolo { get; set; }
public int ExArticolo { get; set; }
public int DocVer { get; set; }
[LenAttribute(255)]
public string Altro { get; set; }
public AttributiDocumento()
{
this.Data = new DateTime(1900, 1, 1);
this.Altro = string.Empty;
}
}
To do exactly what you are asking for you need to cast oAttributiDocumentoList to the (IEnumerable<SqlDataRecord>) like this:
var x = ((IEnumerable<SqlDataRecord>)oAttributiDocumentoList).GetEnumerator();
But there are some disadvantages working with Enumerators.
Usually you need to access elements of your enumerable. To do so just use foreach loop.
foreach(var record in ((IEnumerable<SqlDataRecord>)oAttributiDocumentoList)) {
//Do whatever you want with record
}
If you still prefer to stick with .GetEnumerator(); do not forget to dispose it at the end or embrace in using.
Related
I need to sort a list by any one of its properties, but i dont know which of these properties it will specifically be sorted on. The Main method below.
static void Main(string[] args)
{
Things<Something> something = new Things<Something>();
something.Add(new Something
{ Thing = "Apartment", Price = 1500000 });
something.Add(new Something
{ Thing = "Bed", Price = 10000 });
something.Add(new Something
{ Thing = "Lamp", Price = 600 });
something.Add(new Something
{ Thing = "Car", Price = 5000000 });
Console.WriteLine("\n\tStuff sorted by description");
something = something.SelectionSort("Thing");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.WriteLine("\n\tStock items sorted by value");
something = something.SelectionSort("Value");
foreach (Something thing in something)
Console.WriteLine("\t" + thing);
Console.Write("\n\tPress any key to exit ...");
Console.ReadKey();
}
I have a struct
public struct Something
{
public string Thing { get; set; }
public decimal Price { get; set; }
}
And a generic container class called things
public class Things<T> : IEnumerable<T>
{
private List<T> lstItems;
public int Count { get { return lstItems.Count; } }
public Things() { lstItems = new List<T>(); }
public Things(List<T> items_) { lstItems = new List<T>(items_); }
public void Add(T item)
{
lstItems.Add(item);
}
public T this[int i]
{
get { return lstItems[i]; }
set { lstItems[i] = value; }
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new System.NotImplementedException();
}
public IEnumerator<T> GetEnumerator()
{
foreach (T item in lstItems)
yield return item;
}
}
An extensions class extends the generic container class
public static class ExtensionsClass
{
private static string SortFiield { get; set; }
private static object GetProperty<T>(T thing, string nameofProp)
{
return thing.GetType().GetProperty(nameofProp).GetValue(thing, null);
}
private static int Compare<T>(T x, T y)
{
IComparable propX = (IComparable)GetProperty(x, SortFiield);
IComparable propY = (IComparable)GetProperty(y, SortFiield);
return propX.CompareTo(propY);
}
public static Things<T> SelectionSort<T>(this Things<T> things, string SORTFIELD)
{
List<T> lsstt = new List<T>(things);
int iIndex;
T temporary;
SortFiield = SORTFIELD;
for (int i = 0; i < lsstt.Count - 1; i++)
{
iIndex = i;
for (int j = i + 1; j < lsstt.Count; j++)
{
string first = GetProperty(lsstt[j], SortFiield).ToString();
string second = GetProperty(lsstt[iIndex], SortFiield).ToString();
if (Compare(first, second) < 0)
iIndex = j;
}
temporary = lsstt[i];
lsstt[i] = lsstt[iIndex];
lsstt[iIndex] = temporary;
}
return new Things<T>(lsstt);
}
}
The problem i am encountering is that get property in the extension class returns null, but i know that the object i am trying to return exists. It is found by the "String first = ...." line but when getproperty is called from the Compare method then it returns null.
You are passing "first", "second" to Compare. In your case both of them are strings and not objects, you need to pass "lsstt[j]" and "lsstt[iIndex]" to it.
if (Compare(lsstt[j], lsstt[iIndex]) < 0)
iIndex = j;
I am trying to read from a .csv file to an object array.
There are other solutions here that give solutions for lists but I cannot seem to make it work for me.
Object definition:
public class DTOClass
{
//declare data members
[DataMember]
public DateTime Date { get; set; }
[DataMember]
public string stock_symbol { get; set; }
[DataMember]
public double stock_price_open { get; set; }
[DataMember]
public double stock_price_close { get; set; }
[DataMember]
public double stock_price_low { get; set; }
[DataMember]
public double stock_price_high { get; set; }
[DataMember]
public double stock_price_adj_close { get; set; }
[DataMember]
public long stock_volume { get; set; }
[DataMember]
public string stock_exchange { get; set; }
}
Instance declaration:
private DTOClass[] _dTOs;
Filter method:
private List<DTOClass> FromCsv(string csvLine, List<DTOClass> rest)
{
DataTable _dt = new DataTable();
string[] values = csvLine.Split(',');
int j = _dt.Rows.Count;
for (int i = 0; i < j; i++)
{
DTOClass dto = new DTOClass();
dto.Date = Convert.ToDateTime(values[0]);
dto.stock_symbol = Convert.ToString(values[1]);
dto.stock_price_open = Convert.ToDouble(values[2]);
dto.stock_price_close = Convert.ToDouble(values[3]);
dto.stock_price_low = Convert.ToDouble(values[4]);
dto.stock_price_high = Convert.ToDouble(values[5]);
dto.stock_price_adj_close = Convert.ToDouble(values[6]);
dto.stock_volume = Convert.ToInt64(values[7]);
dto.stock_exchange = Convert.ToString(values[8]);
rest.Add(dto);
}
return rest;
}
Calling filter:
DTO = File.OpenText(Filename).ReadLine().Select(v => FromCsv(v.ToString(),
_restDto)).ToArray();
I need this to return to an object array because it then goes into a CollectionView on a datagrid.
But I keep getting this error:
"Cannot implicitly convert type 'System.Collections.Generic.List[]' to 'MBM.Services.DTOClass[]'"
I know that I'm obviously returning a list of a list, but I've tried other methods that are offered and I'm simply stumped.
I've also tried this:
private static DataTable GetDataTableFromCSVFile(string csv_file_path)
{
DataTable csvData = new DataTable();
try
{
using (TextFieldParser csvReader = new TextFieldParser(csv_file_path))
{
csvReader.SetDelimiters(new string[] { "," });
//csvReader.HasFieldsEnclosedInQuotes = true;
string[] colFields = csvReader.ReadFields();
foreach (string column in colFields)
{
DataColumn datecolumn = new DataColumn(column);
datecolumn.AllowDBNull = true;
csvData.Columns.Add(datecolumn);
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
//Making empty value as null
for (int i = 0; i < fieldData.Length; i++)
{
if (fieldData[i] == "")
{
fieldData[i] = null;
}
}
csvData.Rows.Add(fieldData);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return csvData;
}
Calling with:
DataTable csvData = GetDataTableFromCSVFile(Filename);
But this doesn't seem to return anything from the file.
Any help is appreciated, thanks.
One simple way will be to split the lines and select them into your new object.
var result = File.ReadAllLines("pathTo.csv")
.Select(line => line.Split(','))
.Select(x => new MyObject {
prop1 = x[0],
prop2 = x[1],
//etc..
})
.ToArray();
There's no point in recreating the wheel, Id just use CsvHelper, it has support for what you're doing in addition to handling malformed CSV's you can additionally set up mapping like so:
public sealed class MyClassMap : ClassMap<MyClass>
{
public MyClassMap()
{
AutoMap();
Map( m => m.CreatedDate ).Ignore();
}
}
Then you can get the object like so:
var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();
Objective: process an object and if the object implements an expected type, I want to change a specific property value (this part is working fine), and I also would like to apply the same logic to all property lists (that I explicit point) that are of the same expected type.
I have the following code:
public abstract class BaseObject
{
public int Id { get; set; }
}
public class Father : BaseObject
{
public DateTime CreatedOn { get; set; }
public string Name { get; set; }
public IEnumerable<ChildA> Children1 { get; set; }
public IEnumerable<ChildB> Children2 { get; set; }
public IEnumerable<ChildA> Children3 { get; set; }
public IEnumerable<ChildB> Children4 { get; set; }
}
public class ChildA : BaseObject
{
public int Val1 { get; set; }
}
public class ChildB : BaseObject
{
public string Name { get; set; }
public int Total { get; set; }
}
I want to process an object by applying some changes on a specific property on the target object and on all property children that I explicit say:
public void Start()
{
var listA = new List<ChildA> { new ChildA { Id = 1, Val1 = 1 }, new ChildA { Id = 2, Val1 = 2 } };
var listB = new List<ChildB> { new ChildB { Id = 1, Name = "1", Total = 1 } };
var obj = new Father { Id = 1, CreatedOn = DateTime.Now, Name = "F1", ChildrenA = listA, ChildrenB = listB };
// I explicit tell to process only 2 of the 4 lists....
ProcessObj(obj, x => new object[] { x.Children1, x.Children2 });
}
I was able to write this function:
public void ProcessObj<T>(T obj, Expression<Func<T, object[]>> includes = null)
{
var objBaseObject = obj as BaseObject;
if (objBaseObject == null) return;
// Here I change the ID - add 100 just as an example....
objBaseObject.Id = objBaseObject.Id + 100;
if (includes == null) return;
var array = includes.Body as NewArrayExpression;
if (array == null) return;
var exps = ((IEnumerable<object>)array.Expressions).ToArray();
for (var i = 0; i < exps.Count(); i++)
{
var name = ((MemberExpression)exps[i]).Member.Name;
var childProperty = obj.GetType().GetProperties(
BindingFlags.Public | BindingFlags.Instance
).FirstOrDefault(prop => prop.Name == name);
if (childProperty == null) continue;
// NOT correct because I think I am getting a copy of the object
// and not pointing to the object in memory (by reference)
var childList = childProperty.GetValue(obj);
// TODO: loop on the list and apply the same logic as the father....
// change the ID field....
}
}
In this prototype I started writing reflection, but I really would like to avoid it if possible....
How can I do this???
Maybe I'm missing something, but it seems like you're complicating the problem by using expression trees. Can you just not use a regular Action and Func delegates to do this? Why do they need to be expression trees? Here's an example just using delegates:
public void ProcessObj<T>(T obj, Func<T, IEnumerable<object>> includes) {
var objBaseObject = obj as BaseObject;
if (objBaseObject == null) return;
// Create a reusable action to use on both the parent and the children
Action<BaseObject> action = x => x.Id += 100;
// Run the action against the root object
action(objBaseObject);
// Get the includes by just invoking the delegate. No need for trees.
var includes = includes(obj);
// Loop over each item in each collection. If the types then invoke the same action that we used on the root.
foreach(IEnumerable<object> include in includes)
{
foreach(object item in include)
{
var childBaseObject = item as BaseObject;
if(childBaseObject != null)
{
action(childBaseObject);
}
}
}
}
Useable just like before:
ProcessObj(obj, x => new object[] { x.Children1, x.Children2 });
No expression trees and no reflection, just regular delegate lambdas.
Hope that helps
I have a class, which is created and populated from an xml string, I've simplified it for example purposes:
[XmlRoot("Person")]
public sealed class Person
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("Location")]
public string Location { get; set; }
[XmlElement("Emails", Type = typeof(PersonEmails)]
public PersonEmails Emails { get; set; }
}
public class PersonEmails
{
[XmlElement("Email", Type = typeof(PersonEmail))]
public PersonEmail[] Emails { get; set; }
}
public class PersonEmail
{
[XmlAttribute("Type")]
public string Type { get; set; }
[XmlText]
public string Value { get; set; }
}
To extract the information, I'm trying to load them into another class, which is simply:
public class TransferObject
{
public string Name { get; set; }
public ObjectField[] Fields { get; set; }
}
public class ObjectField
{
public string Name { get; set; }
public string Value { get; set; }
}
I'm only populating "Fields" from the other object, which would simply be (Name = "Location", Value = "London"), but for Emails, (Name = "Email"+Type, Value = jeff#here.com)
Currently I can populate all the other fields, but I'm stuck with Emails, and knowing how to dig deep enough to be able to use reflection (or not) to get the information I need. Currently I'm using:
Person person = Person.FromXmlString(xmlString);
List<ObjectField> fields = new List<ObjectField>();
foreach (PropertyInfo pinfo in person.getType().GetProperties()
{
fields.Add(new ObjectField { Name = pinfo.Name, Value = pinfo.getValue(person, null).ToString();
}
How can I expand on the above to add all my emails to the list?
You are trying to type cast a complex values type to string value so you lost the data. Instead use following code:
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Name = "Person One";
person.Location = "India";
person.Emails = new PersonEmails();
person.Phones = new PersonPhones();
person.Emails.Emails = new PersonEmail[] { new PersonEmail() { Type = "Official", Value = "xyz#official.com" }, new PersonEmail() { Type = "Personal", Value = "xyz#personal.com" } };
person.Phones.Phones = new PersonPhone[] { new PersonPhone() { Type = "Official", Value = "789-456-1230" }, new PersonPhone() { Type = "Personal", Value = "123-456-7890" } };
List<ObjectField> fields = new List<ObjectField>();
fields = GetPropertyValues(person);
}
static List<ObjectField> GetPropertyValues(object obj)
{
List<ObjectField> propList = new List<ObjectField>();
foreach (PropertyInfo pinfo in obj.GetType().GetProperties())
{
var value = pinfo.GetValue(obj, null);
if (pinfo.PropertyType.IsArray)
{
var arr = value as object[];
for (var i = 0; i < arr.Length; i++)
{
if (arr[i].GetType().IsPrimitive)
{
propList.Add(new ObjectField() { Name = pinfo.Name + i.ToString(), Value = arr[i].ToString() });
}
else
{
var lst = GetPropertyValues(arr[i]);
if (lst != null && lst.Count > 0)
propList.AddRange(lst);
}
}
}
else
{
if (pinfo.PropertyType.IsPrimitive || value.GetType() == typeof(string))
{
propList.Add(new ObjectField() { Name = pinfo.Name, Value = value.ToString() });
}
else
{
var lst = GetPropertyValues(value);
if (lst != null && lst.Count > 0)
propList.AddRange(lst);
}
}
}
return propList;
}
}
Check this snippet out:
if(pinfo.PropertyType.IsArray)
{
// Grab the actual instance of the array.
// We'll have to use it in a few spots.
var array = pinfo.GetValue(personObject);
// Get the length of the array and build an indexArray.
int length = (int)pinfo.PropertyType.GetProperty("Length").GetValue(array);
// Get the "GetValue" method so we can extact the array values
var getValue = findGetValue(pinfo.PropertyType);
// Cycle through each index and use our "getValue" to fetch the value from the array.
for(int i=0; i<length; i++)
fields.Add(new ObjectField { Name = pinfo.Name, Value = getValue.Invoke(array, new object[]{i}).ToString();
}
// Looks for the "GetValue(int index)" MethodInfo.
private static System.Reflection.MethodInfo findGetValue(Type t)
{
return (from mi in t.GetMethods()
where mi.Name == "GetValue"
let parms = mi.GetParameters()
where parms.Length == 1
from p in parms
where p.ParameterType == typeof(int)
select mi).First();
}
You can definately do it with Reflection... You can take advantage of the fact that a Type can tell you if it's an array or not (IsArray)... and then take advantage of the fact that an Array has a method GetValue(int index) that will give you a value back.
Per your comment
Because Emails is a property within a different class, recursion should be used. However the trick is knowing when to go to the next level. Really that is up to you, but
if it were me, I would use some sort of Attribute:
static void fetchProperties(Object instance, List<ObjectField> fields)
{
foreach(var pinfo in instance.GetType().GetProperties())
{
if(pinfo.PropertyType.IsArray)
{
... // Code described above
}
else if(pinfo.PropertyType.GetCustomAttributes(typeof(SomeAttribute), false).Any())
// Go the next level
fetchProperties(pinfo.GetValue(instance), fields);
else
{
... // Do normal code
}
}
}
I have this LINQ statement that tries to set the 1st element in the collection of string[]. But it doesn't work.
Below is the LINQ statement.
docSpcItem.Where(x => x.DocID == 2146943)
.FirstOrDefault()
.FinishingOptionsDesc[0] = "new value";
public string[] FinishingOptionsDesc
{
get
{
if (this._FinishingOptionsDesc != null)
{
return (string[])this._FinishingOptionsDesc.ToArray(typeof(string));
}
return null;
}
set { this._FinishingOptionsDesc = new ArrayList(value); }
}
What's wrong with my LINQ statement above?
Couple of things.. There are some problems with your get and set. I would just use auto properties like this..
public class DocSpcItem
{
public string[] FinishingOptionsDesc { get; set; }
public int DocID { get; set; }
}
Next for your linq statement, depending on the presence of an item with an id of 2146943 you might be setting a new version of the object rather than the one you intended. This should work..
[TestMethod]
public void Linq()
{
var items = new List<DocSpcItem>();
//2146943
for (var i = 2146930; i <= 2146950; i++)
{
items.Add(new DocSpcItem()
{ DocID = i
, FinishingOptionsDesc = new string[]
{ i.ToString() }
}
);
}
var item = items.FirstOrDefault(i => i.DocID == 2146943);
if (item != null)
{
item.FinishingOptionsDesc = new string[]{"The New Value"};
}
}
and
public class DocSpcItem
{
public string[] FinishingOptionsDesc { get; set; }
public int DocID { get; set; }
}