i need to get value of property in C# with reflection .
i need to find lenght of string and compare to max .
i write this code :
public static bool ValidateWithReflection(T model)
{
bool validate = false;
var cls = typeof(T);
PropertyInfo[] propertyInfos = cls.GetProperties();
foreach (PropertyInfo item in propertyInfos)
{
var max = item.GetCustomAttributes<MaxLenghtName>().Select(x => x.Max).FirstOrDefault();
if (max != 0)
{
var lenght = item.GetType().GetProperty(item.Name).GetValue(cls, null);
if ((int)lenght > max)
{
return validate = true;
}
}
}
return validate;
}
and this for get value of property :
var lenght = item.GetType().GetProperty(item.Name).GetValue(cls, null);
but it show me this error :
Message "Object does not match target type." string
now whats the problem ? how can i solve this problem ?
What is item.GetType().GetProperty(item.Name) supposed to do? item is a PropertyInfo instance. You're not looking to get properties of that, but of your model.
So simplify your code to this:
var value = item.GetValue(model) as string;
if (value?.Length > max)
{
return validate = true;
}
Related
How to determine whether it is an enum type using Mono.Cecil??
It's easy to determine just using Type.IsEnum. But I can not find any similar functions in TypeDefinition...
Is there any way to determine?
There's an IsEnum property on TypeDefinition.
Oh, and before you ask your next question, here's how you parse an enum string back to it's int value, using Cecil...
int ParseEnum(TypeReference enumRef, string value)
{
var enumDef = enumRef.Resolve();
if (!enumDef.IsEnum)
throw new InvalidOperationException();
int? result = null;
foreach (var v in value.Split(',')) {
foreach (var field in enumDef.Fields) {
if (field.Name == "value__")
continue;
if (field.Name == v.Trim())
result = (result ?? 0) | (int)field.Constant;
}
}
if (result.HasValue)
return result.Value;
throw new Exception(string.Format("Enum value not found for {0}", value));
}
Is there a cleaner way to get a list count using reflection then this?
Boolean include = false;
foreach (PropertyInfo item in props)
{
var pt = item.PropertyType;
String listType = pt.GetGenericArguments()[0].Name;
// Is there a better solution than this?
switch (listType)
{
case "jsonResult":
var list = v as List<jsonResult>;
include = list.count > 0;
break;
}
}
)
I've tried a variety of ideas from Googling but haven't had any luck.
I didn't completely understand what is the "v" variable, but if it is an object and when it's a collection you want to get its count, you can do that this way:
var count = GetCount(v);
if (!count.HasValue)
continue; // Or any other code here
include = count.Value > 0;
The "GetCount" method:
private static int? GetCount(object #object)
{
var collection = #object as System.Collections.ICollection;
if (collection == null)
return null;
return collection.Count;
}
I'm playing around a bit with determining the default values of objects, based on the example here:
https://stackoverflow.com/a/3195792/1293496
This particular extension method was created for System.Type. What I was trying to accomplish was to make this even more generic, where I could do something like this:
int i = 3;
bool amIaDefaultValue = i.IsDefaultValue();
I would expect this to return true if i == 0 (the default value for an int), and false for all other instances.
Here is my initial attempt:
public static bool IsDefaultValue<T>(this T value)
{
var t = typeof(T); // always comes back as object..?
if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
{
return value.Equals(Activator.CreateInstance<T>());
}
else
{
var defaultValue = default(T);
if (value == null)
return defaultValue == null;
else
return value.Equals(defaultValue);
}
}
On the plus side, I'm able to attach .IsDefaultValue() to any object. Unfortunately, the type of T always comes back as System.Object. I can get the correct type if I set it up this way:
var t = typeof(value);
But if the value happens to be null, I'll get an error straight away. Is there a good workaround for implementing an extension method like this? Or should I stick to the tried and tested route from the example?
Edit
As pointed out by comments, it seems I oversimplified this a bit and missed the root of the problem. Here's what was actually calling my IsDefaultValue():
foreach (var imprintProperty in deltas.GetType().GetProperties())
{
var value = imprintProperty.GetValue(deltas);
if (!value.IsDefaultValue())
{
// get corresponding prop in programmable area
var programmableProp = progarea.GetType().GetProperty(imprintProperty.Name);
if (programmableProp != null)
programmableProp.SetValue(progarea, value);
}
}
And now it becomes obvious that .GetValue is always returning as System.Object. Uff.
Is it still possible to treat the object as its underlying type in the extension method? Sorry for the confusion with this.
Take a look at this:
static class Program
{
static void Main()
{
int a = 1;
Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());
a = 0;
Console.WriteLine("a.IsDefaultValue() : " + a.IsDefaultValue());
object obj = new object();
Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());
obj = null;
Console.WriteLine("obj.IsDefaultValue() : " + obj.IsDefaultValue());
int? b = 1;
Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());
b = null;
Console.WriteLine("b.IsDefaultValue() : " + b.IsDefaultValue());
Console.ReadKey(true);
}
static bool IsDefaultValue<T>(this T value)
{
if (ReferenceEquals(value, null))
{
return true;
}
var t = value.GetType();
if (t.IsValueType)
{
return value.Equals(Activator.CreateInstance(value.GetType()));
}
return false;
}
}
Apparently works (I've to say that I was convinced that the other way should have worked but not)
I've been tasked with finding the Type and Length of a specific column from the DBML.
I would like to pass in the DataContext, TableName and then ColumnName to return my values that I'm looking for. I found the following example of something similar, but it isn't returning anything:
http://www.codeproject.com/Articles/27392/Using-the-LINQ-ColumnAttribute-to-Get-Field-Length
However, I may be implementing this incorrectly. for the obj parameter should I pass in the DataContext? I've found that when I try to load up the info (object array) I get nothing...
public static int GetLengthLimit(object obj, string field)
{
int dblenint = 0; // default value = we can't determine the length
Type type = obj.GetType();
PropertyInfo prop = type.GetProperty(field);
// Find the Linq 'Column' attribute
// e.g. [Column(Storage="_FileName", DbType="NChar(256) NOT NULL", CanBeNull=false)]
object[] info = prop.GetCustomAttributes(typeof(ColumnAttribute), true);
// Assume there is just one
if (info.Length == 1)
{
ColumnAttribute ca = (ColumnAttribute)info[0];
string dbtype = ca.DbType;
if (dbtype.StartsWith("NChar") || dbtype.StartsWith("NVarChar") || dbtype.StartsWith("VarChar"))
{
int index1 = dbtype.IndexOf("(");
int index2 = dbtype.IndexOf(")");
string dblen = dbtype.Substring(index1 + 1, index2 - index1 - 1);
int.TryParse(dblen, out dblenint);
}
}
return dblenint;
}
No you pass an instance of one of the entities.
I would actually change that to take a Type as a parameter, not an instance.
For a given entity, This method will generate a dictionary of string fields' length (LinqToSQL syntax):
public static Dictionary<string, int> GetStrFieldsLen()
{
Dictionary<string, int> dicFieldLen = new Dictionary<string, int>();
var myEntity = new myEntity();
foreach(var m in myEntity.GetType().GetProperties())
{
var typeName = myEntity.GetType().GetProperty(m.Name).PropertyType;
int iLen = 0;
if (typeName == typeof(string))
{
var tv= (m.CustomAttributes).First().NamedArguments.ToArray()[0].TypedValue.ToString(); // Get DbType member
int idxStart = tv.LastIndexOf("(") + 1;
if (int.TryParse(tv.Substring(idxStart, tv.LastIndexOf(")") - idxStart), out iLen)==false)
iLen= int.MaxValue; // Field length is MAX
dicFieldLen.Add(m.Name, iLen);
}
}
return dicFieldLen ;
}
I want to write the property names and matching data to a delimited file, I've copied some code from the c# objectdumper help file and it all seems to work OK but I dont understand reflection enough to be confident to use it. What I'm worried about is an incorrect value being placed in the incorrect column, is it possible for this to happen e.g.
Field1,Field2
Val1,Val2
Val1,Val2
Val2,Val1 << Could this ever happen ?
Also what does this piece of code mean?
f != null ? f.GetValue(this) : p.GetValue(this, null)
Code below:
public string returnRec(bool header, string delim)
{
string returnString = "";
bool propWritten = false;
MemberInfo[] members = this.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (MemberInfo m in members)
{
FieldInfo f = m as FieldInfo;
PropertyInfo p = m as PropertyInfo;
if (f != null || p != null)
{
if (propWritten)
{
returnString += delim;
}
else
{
propWritten = true;
}
if (header)
returnString += m.Name;
else
{
Type t = f != null ? f.FieldType : p.PropertyType;
if (t.IsValueType || t == typeof(string))
{
returnString += f != null ? f.GetValue(this) : p.GetValue(this, null);
}
}
}
}
return returnString;
}
Type t = f != null ? f.FieldType : p.PropertyType;
this is an inline if, asking is f != null then f.FieldType else p.PropertyType
can be written as
Type t;
if (f != null)
t = f.FieldType;
else
t = p.PropertyType;
#astander and #Frederik have essentially answered the questions and concerns that you specifically voiced, but I'd like to suggest doing things in a slightly more efficient manner. Depending on the number of object instances that you wish to write to your file, the method that you've presented may end up being quite inefficient. That's because you're gleaning type and value information via reflection on every iteration, which is unnecessary.
What you're looking for is something that looks up type information once, and then only uses reflection to get the value of properties and fields, e.g. (.NET 3.5),
public static IEnumerable<string> ReturnRecs(IEnumerable items, bool returnHeader, string delimiter)
{
bool haveFoundMembers = false;
bool haveOutputHeader = false;
PropertyInfo[] properties = null;
FieldInfo[] fields = null;
foreach (var item in items)
{
if (!haveFoundMembers)
{
Type type = item.GetType();
properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(pi => pi.PropertyType.IsValueType || pi.PropertyType == typeof (string)).ToArray();
fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(fi => fi.FieldType.IsValueType || fi.FieldType == typeof(string)).ToArray();
haveFoundMembers = true;
}
if (!haveOutputHeader)
{
yield return String.Join(delimiter, properties.Select(pi => pi.Name)
.Concat(fields.Select(pi => pi.Name)).ToArray());
haveOutputHeader = true;
}
yield return String.Join(delimiter,
properties.Select(pi => pi.GetValue(item, null).ToString())
.Concat(fields.Select(fi => fi.GetValue(item).ToString())).ToArray());
}
The above code only ever performs a GetProperties and GetFields once per group of records--also, because of this, there's no need to explicitly sort the properties and fields as was #Frederik's suggestion.
#astander has already given you an answer on the Type t = f != null ? f.FieldType : p.PropertyType; question, so I will leave that one out. Regarding getting the values into the correct columns, I don't know wheter reflection guarantees to list the members of a type in a specific order, but you can guarantee it by sorting the list before using it (using Linq):
MemberInfo[] members = typeof(Item).GetMembers(BindingFlags.Public | BindingFlags.Instance);
IEnumerable<MemberInfo> sortedMembers = members.OrderBy(m => m.Name);
foreach (MemberInfo member in sortedMembers)
{
// write info to file
}
Or if you prefer a non-Linq approach (works with .NET Framework 2.0):
MemberInfo[] members = typeof(Item).GetMembers(BindingFlags.Public | BindingFlags.Instance);
Array.Sort(members, delegate(MemberInfo x, MemberInfo y){
return x.Name.CompareTo(y.Name);
});
foreach (MemberInfo member in members)
{
// write info to file
}
Just to add some thoughts re the accepted answer, in particular for large data volumes:
PropertyInfo etc can be unnecessarily slow; there are ways to avoid this, for example using HyperDescriptor or other dynamic code
rather than building lots of intermediate strings, it may be more efficient to write output directly to a TextWriter
As a tweaked version that adopts these approaches, see below; note that I haven't enabled HyperDescriptor in this example, but that is just:
HyperTypeDescriptionProvider.Add(typeof(YourType));
Anyway...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
static class Program {
static void Main() { // just some test data...
var data = new[] { new { Foo = "abc", Bar = 123 }, new { Foo = "def", Bar = 456 } };
Write(data, Console.Out, true, "|");
}
public static void Write<T>(IEnumerable<T> items, TextWriter output, bool writeHeaders, string delimiter) {
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
foreach (T item in items) {
bool firstCol = true;
if (writeHeaders) {
foreach (PropertyDescriptor prop in properties) {
if (firstCol) {
firstCol = false;
} else {
output.Write(delimiter);
}
output.Write(prop.Name);
}
output.WriteLine();
writeHeaders = false;
firstCol = true;
}
foreach (PropertyDescriptor prop in properties) {
if (firstCol) {
firstCol = false;
} else {
output.Write(delimiter);
}
output.Write(prop.Converter.ConvertToString(prop.GetValue(item)));
}
output.WriteLine();
}
}
}