I want to make a own parser that can parse object values into the <T> Type that contains class with propertys.
the class ASObject is just a Dictionary<string, object>
public class Example {
public string User { get; set; }
public int Id { get; set; }
}
public static class ServiceResultParser<T>
{
public static T Parse(ASObject AS)
{
foreach(var l in AS.Values)
{
}
}
}
Usage:
var Result = ServiceResultParser.Parse<Example>(theobject);
string User = Result.User;
that is only a test class that I called Example
in json we can use JsonConvert.DeserializeObject<T>(value)
and no I dont want parse json.
how can I now parse the value into the Example class?
regarding.
You could check wheter T has a property with a name that matches the Dictionary's key:
public static class ServiceResultParser<T> where T : new()
{
public static T Parse(ASObject AS)
{
var temp = GetObject();
foreach(var l in AS)
{
PropertyInfo[] properties = typeof(T).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name == l.Key) property.SetValue(temp, l.Value);
}
}
return temp;
}
protected T GetObject()
{
return new T();
}
}
You should also check if the properties type match, etc...
Related
I want to write a generic function that can print any certain property values. One parameter is a list of random class, another parameter is an array of certain class property names. The function is able to print given property value of each element in the list.
Assuming I have two classes of two lists of them:
class visitor {
public string name;
public string age;
public string address;
public string nationality;
}
class menu {
public string dish;
public double prise;
public string chef;
public bool isForVIP;
}
List<visitor> visitorList, List<menu> menuList
Now I want only the function void GenericOutput(List<AnyObject> objList,string[] certainProperties) to output a part of each class properties. For example:
GenericOutput(visitorList,new string[]{ "name","age" });
GenericOutput(menuList,new string[]{ "dish","double","isForVIP" });
How can I design the function in C#? Could some help me?
By using reflection, you can:
Create a generic method.
Get the run time type from the generic type argument.
Get information about the properties of the type.
Extract the values from each object of the type.
Example:
public void GenericOutput<T>(List<T> objects, string[] propertyNames)
{
// Get the generic type.
Type type = typeof(T);
// Get the requested properties of the type.
var propertyInfos = propertyNames.Select(pn => type.GetProperty(pn));
foreach (var obj in objects)
{
foreach (var propertyInfo in propertyInfos)
{
// For each given object, iterate the properties of
// the type and get the property value from the object.
var value = propertyInfo.GetValue(obj);
// Print or do whatever with the value...
Console.WriteLine(value);
}
}
}
Try this,
class Program
{
static void Main(string[] args)
{
var visitors = new List<Visitor>()
{
new Visitor(){Name="Visitor1",Age="30",Address="adress1",Nationality="Nationality1"},
new Visitor(){Name="Visitor2",Age="20",Address="adress2",Nationality="Nationality2"},
new Visitor(){Name="Visitor3",Age="10",Address="adress3",Nationality="Nationality3"},
new Visitor(){Name="Visitor4",Age="50",Address="adress4",Nationality="Nationality4"},
new Visitor(){Name="Visitor5",Age="90",Address="adress5",Nationality="Nationality5"},
};
GenericOutput(visitors, new string[] { "Name", "Age", "Address" });
Console.ReadKey();
}
private static void GenericOutput<T>(List<T> obj, string[] properties)
{
var t = typeof(T);
foreach (var item in obj)
{
foreach (var propName in properties)
{
var propValue = (t.GetProperty(propName).GetValue(item) ?? string.Empty).ToString();
Console.WriteLine($"{propName}:{propValue}");
}
Console.WriteLine("-----------");
}
}
}
class Visitor
{
public string Name { get; set; }
public string Age { get; set; }
public string Address { get; set; }
public string Nationality { get; set; }
}
Result:
I have a generic method that can be called with 2 different object types, TypeA or TypeB. TypeA and TypeB are essentially identical classes except in name only. I am trying to determine how to prevent from having to duplicate the Foreach loop code for each object type. Is this possible ? thanks.
public class TypeA
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
public class TypeB
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
private CsvExport GenerateExport<T>(IEnumerable<T> scores)
{
CsvExport export = new CsvExport();
List<TypeA> aList = null;
List<TypeB> bList = null;
Type type = scores.GetType();
if (type.FullName.Contains("TypeA"))
{
aList = scores as List<ObjectaModel>;
}
else if (type.FullName.Contains("TypeB"))
{
bList = scores as List<ObjectbModel>;
}
foreach (var dt in aList)
{
export.AddRow();
export["Name"] = dt.Name;
export["Department"] = dt.Department;
export["Total "] = dt.Total;
};
return export;
}
In this particular case I strongly suggest you delegate the hard work to the CsvHelper library which you can also obtain from Nuget and is used like this...
public void ExportToCsv<T>(string filename, ImmutableArray<T> objects)
{
using (var writer = File.CreateText(filename))
{
var csv = new CsvWriter(writer);
csv.WriteRecords(objects);
}
}
The more general answer to your question is that you must either have both classes inherit from a common class or interface or you would have to use reflection to look for an obtain the values of the named properties.
Using a common interface...
public interface IScore
{
int HiScore {get;}
}
public class ScrabbleScore : IScore
{
public int HiScore {get;set;}
}
public class PacManScore : IScore
{
public int HiScore {get;set;}
}
public void Export<T>(IEnumerable<T> scores) where T: IScore
{
foreach(var s in scores)
{
CvsExport["Hi score"]= s.HiScore;
}
}
Using reflection...
var CsvExport = new Dictionary<string,string>();
foreach(var o in scores)
{
//note that checking the type for each object enables you to have heterogenous lists if you want
var objectType= o.GetType();
foreach(var p in objectType.GetProperties())
{
var propertyName = p.Name;
CsvExport[propertyName] = p.GetValue(o).ToString();
}
}
I would treat the reflection solution as the least favoured of the three.
I need to obtain a PropertyDescriptorCollection with all properties that are decorated with a custom attribute. The problem is that TypeDescriptor.GetProperties can only filter by an exact matching of all Attribute's properties, so if I want to get all properties no matter how attribute's properties are set, I would have to cover all the possibilities in the filter array.
Here is the code for my attribue:
[AttributeUsage(AttributeTargets.Property)]
class FirstAttribute : Attribute
{
public bool SomeFlag { get; set; }
}
And a class with decorated properties:
class Foo
{
[First]
public string SomeString { get; set; }
[First(SomeFlag = true)]
public int SomeInt { get; set; }
}
And main:
static void Main(string[] args)
{
var firstPropCollection = TypeDescriptor.GetProperties(typeof(Foo), new Attribute[] {new FirstAttribute()});
Console.WriteLine("First attempt: Filtering by passing an array with a new FirstAttribute");
foreach (PropertyDescriptor propertyDescriptor in firstPropCollection)
{
Console.WriteLine(propertyDescriptor.Name);
}
Console.WriteLine();
Console.WriteLine("Second attempt: Filtering by passing an an array with a new FirstAttribute with object initialization");
var secondPropCollection = TypeDescriptor.GetProperties(typeof(Foo), new Attribute[] { new FirstAttribute {SomeFlag = true} });
foreach (PropertyDescriptor propertyDescriptor in secondPropCollection)
{
Console.WriteLine(propertyDescriptor.Name);
}
Console.WriteLine();
Console.WriteLine("Third attempt: I am quite ugly =( ... but I work!");
var thirdCollection = TypeDescriptor.GetProperties(typeof(Foo)).Cast<PropertyDescriptor>()
.Where(p => p.Attributes.Cast<Attribute>().Any(a => a.GetType() == typeof(FirstAttribute)));
foreach (PropertyDescriptor propertyDescriptor in thirdCollection)
{
Console.WriteLine(propertyDescriptor.Name);
}
Console.ReadLine();
}
So far, the only way I have made it worked is the third attempt, I wonder if there is a more intuitive and elegant way.
The output is the following:
As you can see I can only manage to get both properties with the last attempt.
I am not really sure that I understand the problem... You want all properties that have a specific attribute regardless of this attributes value?
class Program
{
static void Main(string[] args)
{
var props = typeof(Foo).GetProperties();
var filtered = props
.Where(x => x.GetCustomAttributes(typeof(FirstAttribute), false).Length > 0)
.ToList();
var propertyDescriptor = TypeDescriptor.GetProperties(typeof(Foo))
.Find(filtered[0].Name, false);
}
}
class Foo
{
[First]
public string SomeString { get; set; }
[First(SomeFlag = true)]
public int SomeInt { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
class FirstAttribute : Attribute
{
public bool SomeFlag { get; set; }
}
So I am using reflection to loop through the properties of one object and populating the values on a different object with properties of the same name. This works great but the problem comes when the property type is a collection. I want to be able to loop through each of the objects in the source collection and populate the same list with objects in the source collection.
public class SourceMessage
{
public string Name { get; set; }
public int Version { get; set; }
public IList<ValueDefinition> Values { get; set; }
}
public class ValueDefinition
{
public string Name { get; set; }
public string Value { get; set; }
}
public class TargetObject
{
public TargetObject()
{
Values = new List<TargetValueDefinition>();
}
public string Name { get; set; }
public int Version { get; set; }
public IList<TargetValueDefinition> Values { get; set; }
}
public class TargetValueDefinition
{
public string Name { get; set; }
public string Value { get; set; }
}
Then I use Reflection to populate the target from the source.
public static void PopulateFromMessage<T, TS>(ref T targetEntity, TS message)
{
var sourceType = typeof(TS);
var targetType = typeof(T);
foreach (var targetPropInfo in targetType.GetProperties())
{
if (sourceType.GetProperty(targetPropInfo.Name) != null)
{
var obj = sourceType.GetProperty(targetPropInfo.Name);
if (obj.PropertyType.Namespace == "System.Collections.Generic")
{
//var x = targetType.GetProperty(targetPropInfo.Name);
//PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
continue;
}
targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
}
}
}
So calling this would be like this:
private void DenormalizeMessage(SourceMessage message)
{
var newTargetObject = new TargetObject();
PopulateFromMessage(ref newTargetObject , message);
}
I can identify when the property is a collection but am uncertain of how to create new TargetValueDefinitions and populate them with the values from ValueDefinitions. In the end it is pretty much a copy of the SourceMessage in the form of a TargetObject.
This all stems from receiving messages and transforming them into objects with the same property names.
If your problem is iterating through items contained inside a single property when it is a collection, then the key would be to read the property value into a dynamic variable and not an object variable that is by default, this way you could use a foreach for it.
dynamic propVal = inputProperty.GetValue(item);
foreach (var subItem in propVal)
{
//do your stuff
}
Disclaimer: This is extremely unsafe to do and makes a lot of assumptions but it should puth you on the right path.
Change you method to this:
public static void PopulateFromMessage<T, TS>(T targetEntity, TS message)
{
var sourceType = typeof (TS);
var targetType = typeof (T);
foreach (var targetPropInfo in targetType.GetProperties())
{
if (targetPropInfo.PropertyType.IsGenericType)
{
if (targetPropInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>))
{
var originalList = sourceType.GetProperty(targetPropInfo.Name).GetValue(message) as IList;
if (originalList != null)
{
var argumentType = targetPropInfo.PropertyType.GetGenericArguments();
var listType = typeof (List<>);
var concreteType = listType.MakeGenericType(argumentType);
var newList = Activator.CreateInstance(concreteType) as IList;
foreach (var original in originalList)
{
var targetValue = Activator.CreateInstance(argumentType[0]);
// do this yourself. Here we're converting ValueDefinition to TargetValueDefinition
// targetValue.Fill(original);
}
targetPropInfo.SetValue(targetEntity, newList);
}
}
}
else
{
if (sourceType.GetProperty(targetPropInfo.Name) != null)
{
var obj = sourceType.GetProperty(targetPropInfo.Name);
if (obj.PropertyType.Namespace == "System.Collections.Generic")
{
//var x = targetType.GetProperty(targetPropInfo.Name);
//PopulateFromMessage(ref x, sourceType.GetProperty(targetPropInfo.Name));
continue;
}
targetPropInfo.SetValue(targetEntity, sourceType.GetProperty(targetPropInfo.Name).GetValue(message), null);
}
}
}
}
You should create a interface for each class (implement the methods and properties on interface) and implement it in each class. After, in function PopulateFromMessage should specify the interface allowed in method, with this you can use directly the properties of class with T and TS generic types.
I have a view model which uses custom attributes such as
public int Id { get; set; }
public string Name { get; set; }
[IsEnumeration(typeof(CaseStatus))]
public string Status { get; set; }
IsEnumeration is a custom attribute which takes an Enumeration superclass as a parameter (actually it takes any type, but that doesn't matter since noone else will be using this)
public class IsEnumerationAttribute : Attribute
{
public Type Enumeration;
public IsEnumerationAttribute(Type enumeration)
{
Enumeration = enumeration;
}
}
What I want is to be able to get the type specified for any parameter. Currently my code looks like this:
public T EnumerationValuesToDisplayNames<T>(T item) where T : new()
{
if (LoggedInUser.IsSuper) return item;
var tProps = typeof (T).GetProperties()
.Where(prop => Attribute
.IsDefined(prop, typeof (IsEnumerationAttribute)));
foreach (var prop in tProps)
{
if (prop.GetValue(item, null) != null)
{
/*
Here I look through all properties with the IsEnumerable attribute.
I want to do something such as:
var type = prop.GetAttribute(item, typeof(IsEnumerable));
var displayName = Enumeration<type>.FromId(prop.GetValue(item, null));
prop.SetValue(item, displayName);
*/
}
}
return item;
}
I hope this makes sense, any help would be greatly appreciated, thanks
Assuming from your post you have a class defined as such:
public class Enumeration<T> {
public static string FromId(string id) {
// FromId Implmentation
}
}
Then you should just need
foreach (var prop in tProps) {
var id=prop.GetValue(item, null);
if (id!=null) {
var type = prop.GetCustomAttributes(typeof(EnumerationAttribute>,true).OfType<EnumerationAttribute>().Select(x=>x.Enumeration).First();
var enumerationType=typeof(Enumeration<>).MakeGenericType(type);
var fromIdMethod=enumerationType.GetMethod("FromId",BindingFlags.Public|BindingFlags.Static|BindingFlags.InvokeMethod);
var displayName=fromIdMethod.Invoke(null,new object[] {id});
prop.SetValue(item, displayName);
}
}
Alternatively you could implement the FromId method directly in the EnumerationAttribute then you could just call it directly like so...
foreach (var prop in tProps) {
var id=prop.GetValue(item, null);
if (id!=null) {
var enumAttrib = prop.GetCustomAttributes(typeof(EnumerationAttribute>,true).OfType<EnumerationAttribute>().First();
var displayName=enumAttrib.FromId((string)id);
prop.SetValue(item, displayName);
}