I query some data via reflection. The returned data type is System.data.datacolumn[] (variable "test"). I would like to convert it into a generic list (e.g. string List). Is that possible?
public IEnumerable<string> GetStringList(string property)
{
var test = GetPropertyValue(SomeObject, property);
// MAGIC //
return test;
}
public object GetPropertyValue(object obj, string propertyName)
{
var propertyNames = propertyName.Split('.');
foreach (var t in propertyNames)
{
if (obj != null)
{
var propertyInfo = obj.GetType().GetProperty(t);
obj = propertyInfo != null ? propertyInfo.GetValue(obj) : null;
}
}
return obj;
}
you can try this
if (test is IEnumerable) {
var values = test as IEnumerable;
//Method 1: convert to list
var asList = values.Cast<object>().ToList();
//Method 2: iterate to IEnumerable and add to List
var asList = new List<object>();
foreach (var value in values)
{
asList.Add(value);
}
}
Related
I have a table with 30 columns,
and it contains 1000 rows.
I want a single LINQ query, which checks for a particular value in all columns and converts the result into a list.
For example:
table.where(allcolumnvalue.contains(searchvalue)).Tolist()
How to accomplish the above using one LINQ query. Any help is much appreciated.
For your request all of fields should have same type, at least in the static typed C#.
The method Queriable.Where gets the Expression<Func<T, bool>> predicate as parameter. So you need build the predicate o.p1 == val || o.p2 == val || o.p3 = val ... as Expression value. Here o is a parameter of Expression<Func<T, bool>>:
public Expression BuildExpression<TObj, TVal>(TObj obj, TVal val)
{
Expression<Func<TObj, bool>> predicate = (o) => o.p1 == val || ... || o.pN == val;
return predicate;
}
but we need build predicate dynamically for all properties of TObj that have type TVal.
To simplify the code we will build equal expression false || o.p1 == val || ... || o.pN == val.
public Expression<Func<TObj, bool>> BuildExpression<TObj, TVal>(TVal val)
{
var parameter = Expression.Parameter(typeof(TObj), "o");
var valExpression = Expression.Constant(val, typeof(TVal));
var body = Expression.Constant(false, typeof(bool));
var properties = typeof(TObj).GetProperties()
.Where(p => p.PropertyType == typeof(TVal));
foreach (var property in properties)
{
var propertyExpression = Expression.Property(parameter, property);
var equalExpression = Expression.Equal(propertyExpression, valExpression);
body = Expression.Or(body, equalExpression);
}
return Expression.Lambda<Func<TObj, bool>>(body, parameter);
}
. . .
using (var dbContext = new DbContext())
{
var whereExpression = BuildExpression<User, string>("foo");
var contaningsFoo = dbContext.Users.Where(whereExpression);
}
I got answer But Is not perfect answer But Is Worked well
public class GenericList<T>
{
void Add(T input) { }
public List<T> SerachFun(List<T> input, string search)
{
List<T> output = new System.Collections.Generic.List<T>();
foreach (var aa in input)
{
var columns = aa.GetType().GetProperties().ToList();
foreach (var bb in columns)
{
var cccc = bb.GetValue(aa);
bool result = cccc.ToString().Contains(search);
if (result)
{
output.Add(aa);
continue;
}
}
}
return output;
}
}
The Generic Class Object Created
public GenericList<table1> g = new GenericList<table1>();
the Generic Class Method Called :
var tabledetails=db.table1.ToList();
var resultcommonsearch = g.SerachFun(tabledetails, "Dhoni");
using code
public class GenericList<T>
{
public List<T> SerachFun(List<T> input, string search)
{
List<T> output = new System.Collections.Generic.List<T>();
foreach (var aa in input)
{
var columns = aa.GetType().GetProperties().ToList();
foreach (var bb in columns)
{
var cccc = bb.GetValue(aa);
if(cccc!=null)
{
bool result = cccc.ToString().Contains(search);
if (result)
{
output.Add(aa);
continue;
}
}
}
}
return output;
}
}
Try call method
public GenericList<table1> g = new GenericList<table1>();
var tabledetails=db.table1.ToList();
var resultcommonsearch = g.SerachFun(tabledetails, "Dhoni");
I have this method which extracts the property name from an expresssion:
private static string GetPropertyName<TObj, TProp>(Expression<Func<TObj, TProp>> prop)
{
var expression = prop.Body as MemberExpression;
if (expression != null)
{
var property = expression.Member as PropertyInfo;
if (property != null)
{
return property.Name;
}
}
return string.Empty;
}
So later I can use it like this:
GetPropertyName((User u) => u.Surname); //Returns "Surname"
I would like to be able to pass a collection of properties instead one by one. Just to be clear, the properties could be of different types.
I am completely agree with #Patrick and its preferred way over mine.
but if you say you are not using the C#6.0 and then you can use the code you have written. I just use the param, yield return and one foreach loop
private static IEnumerable<string> GetPropertyName<TObj, TProp>(params Expression<Func<TObj, TProp>>[] propCollection)
{
foreach (var prop in propCollection)
{
var expression = prop.Body as MemberExpression;
if (expression != null)
{
var property = expression.Member as PropertyInfo;
if (property != null)
{
yield return property.Name;
}
}
yield return string.Empty;
}
}
UPDATE
First One ask you to specific the type of the object again and again mean you have to provide the full length expression again.
Try the below it will ask you to specify the property as much as you want in one Expression only.
public static IEnumerable<string> GetPropertiesName<TObj, TProp>(Expression<Func<TObj, TProp[]>> prop)
{
var array = (prop.Body as NewArrayExpression);
var exp = array == null ? null : array.Expressions;
if (exp != null)
{
//var expArr = (prop.Body as NewArrayExpression).Expressions;
foreach (var oneProp in exp)
{
Expression onePropExp;
if (oneProp.GetType() == typeof (UnaryExpression))
{
onePropExp = (oneProp as UnaryExpression).Operand;
}
else
{
onePropExp = oneProp;
}
var property = (onePropExp as MemberExpression).Member as PropertyInfo;
if (property != null)
{
yield return property.Name;
}
yield return string.Empty;
}
}
yield return string.Empty;
}
You can call it like -
var propNames = GetPropertiesName((AllSubsTransAndDevices d) => new[]
{
d.CurrentDriverId,
d.GPSDevicesId,
d.TransporterId
});
It might be me, but I think you don't need to do this the hard way. You can simply use the C# 6 nameof keyword. This assumes you can use C# 6 of course.
string name = nameof(u.Surname);
Try this:
Usage: string[] props = GetPropertiesName((MainWindow m) => m.Lalala, (MainWindow m) => m.Lalala);
private static string[] GetPropertiesName<TObj, TProp>(params Expression<Func<TObj, TProp>>[] prop)
{
List<string> ret = new List<string>();
foreach (var item in prop)
ret.Add(GetPropertyName(item));
return ret.ToArray();
}
private static string GetPropertyName<TObj, TProp>(Expression<Func<TObj, TProp>> prop)
{
var expression = prop.Body as MemberExpression;
if (expression != null)
{
var property = expression.Member as PropertyInfo;
if (property != null)
{
return property.Name;
}
}
return string.Empty;
}
I have this function:
the variable c obtains all the properties of my class <T>
in this case:
c ->
Id
Key
Value
public List<T> ReadStoreProceadure<T>(string storeName)
{
var result = new List<T>();
var instance = (T) Activator.CreateInstance(typeof (T), new object[] {});
var c = typeof (T);
var data = DataReader.ReadStoredProceadures(_factibilidad, storeName); // This part is returning verified data and it's ok
while (data.Read())
{
if (data.HasRows)
{
foreach (var item in c.GetProperties())
{
//item.SetValue(c, item.Name, null);
}
}
}
}
How I can add these values to my instance instance and add it to my result variable?
It's possible?
I've created an extension method for IDataReader that does essentially what I believe you're trying to do:
public static List<T> ToList<T>(this IDataReader dr) where T: new()
{
var col = new List<T>();
var type = typeof(T);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
while (dr.Read())
{
var obj = new T();
for (int i = 0; i < dr.FieldCount; i++)
{
string fieldName = dr.GetName(i);
var prop = props.FirstOrDefault(x => x.Name.ToLower() == fieldName.ToLower());
if (prop != null)
{
if (dr[i] != DBNull.Value)
{
prop.SetValue(obj, dr[i], null);
}
}
}
col.Add(obj);
}
dr.Close();
return col;
}
However, you'll notice I've chosen to work the from the other way around. Instead of iterating the type's properties and fetching them from the DataReader, I iterate the DataReader columns and check for a matching property on the type. You should be able to quickly modify this to fit your data retrieval scheme.
I'm trying to get a Byte[] using reflection. Unfortunately the result it always NULL. The property is filled with data. Here's my code snippet.
public static void SaveFile(BusinessObject document)
{
Type boType = document.GetType();
PropertyInfo[] propertyInfo = boType.GetProperties();
Object obj = Activator.CreateInstance(boType);
foreach (PropertyInfo item in propertyInfo)
{
Type xy = item.PropertyType;
if (String.Equals(item.Name, "Content") && (item.PropertyType == typeof(Byte[])))
{
Byte[] content = item.GetValue(obj, null) as Byte[];
}
}
return true;
}
Here's the working code:
public static void SaveFile(BusinessObject document)
{
Type boType = document.GetType();
PropertyInfo[] propertyInfo = boType.GetProperties();
foreach (PropertyInfo item in propertyInfo)
{
if (String.Equals(item.Name, "Content") && (item.PropertyType == typeof(Byte[])))
{
Byte[] content = item.GetValue(document, null) as Byte[];
}
}
}
Your code looks strange. You are creating a new instance of the type of the parameter and try to get the value from that instance. You should be using the parameter itself instead:
public static void SaveFile(BusinessObject document)
{
Type boType = document.GetType();
PropertyInfo[] propertyInfo = boType.GetProperties();
foreach (PropertyInfo item in propertyInfo)
{
Type xy = item.PropertyType;
if (String.Equals(item.Name, "Content") &&
(item.PropertyType == typeof(Byte[])))
{
Byte[] content = item.GetValue(document, null) as Byte[];
}
}
}
BTW:
return true in a method that returns void is illegal and will lead to a compiler error.
There is no need to use reflection in your case. You could simply write this:
public static void SaveFile(BusinessObject document)
{
Byte[] content = document.Content;
// do something with content.
}
This is only true if Content is defined on BusinessObject and not only on derived classes.
from your code snippet it appears you are not populating any value.
Object obj = Activator.CreateInstance(boType);
this would just invoke the default consturctor and assign default values for all types.
and for byte[] it is null
it should be
item.GetValue(document, null)
How to convert IEnumerable to ObservableCollection?
As per the MSDN
var myObservableCollection = new ObservableCollection<YourType>(myIEnumerable);
This will make a shallow copy of the current IEnumerable and turn it in to a ObservableCollection.
If you're working with non-generic IEnumerable you can do it this way:
public ObservableCollection<object> Convert(IEnumerable original)
{
return new ObservableCollection<object>(original.Cast<object>());
}
If you're working with generic IEnumerable<T> you can do it this way:
public ObservableCollection<T> Convert<T>(IEnumerable<T> original)
{
return new ObservableCollection<T>(original);
}
If you're working with non-generic IEnumerable but know the type of elements, you can do it this way:
public ObservableCollection<T> Convert<T>(IEnumerable original)
{
return new ObservableCollection<T>(original.Cast<T>());
}
To make things even more simple you can create an Extension method out of it.
public static class Extensions
{
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> col)
{
return new ObservableCollection<T>(col);
}
}
Then you can call the method on every IEnumerable
var lst = new List<object>().ToObservableCollection();
ObservableCollection<decimal> distinctPkgIdList = new ObservableCollection<decimal>();
guPackgIds.Distinct().ToList().ForEach(i => distinctPkgIdList.Add(i));
// distinctPkgIdList - ObservableCollection
// guPackgIds.Distinct() - IEnumerable
The C# Function to Convert the IEnumerable to ObservableCollection
private ObservableCollection<dynamic> IEnumeratorToObservableCollection(IEnumerable source)
{
ObservableCollection<dynamic> SourceCollection = new ObservableCollection<dynamic>();
IEnumerator enumItem = source.GetEnumerator();
var gType = source.GetType();
string collectionFullName = gType.FullName;
Type[] genericTypes = gType.GetGenericArguments();
string className = genericTypes[0].Name;
string classFullName = genericTypes[0].FullName;
string assName = (classFullName.Split('.'))[0];
// Get the type contained in the name string
Type type = Type.GetType(classFullName, true);
// create an instance of that type
object instance = Activator.CreateInstance(type);
List<PropertyInfo> oProperty = instance.GetType().GetProperties().ToList();
while (enumItem.MoveNext())
{
Object instanceInner = Activator.CreateInstance(type);
var x = enumItem.Current;
foreach (var item in oProperty)
{
if (x.GetType().GetProperty(item.Name) != null)
{
var propertyValue = x.GetType().GetProperty(item.Name).GetValue(x, null);
if (propertyValue != null)
{
PropertyInfo prop = type.GetProperty(item.Name);
prop.SetValue(instanceInner, propertyValue, null);
}
}
}
SourceCollection.Add(instanceInner);
}
return SourceCollection;
}