I use FastMember to get values out of objects and nested objects. If a property is a string or int everything works fine. But now I want to get the values also for collections. Here is my code so far:
// Set accessor
var sourceAccessor = ObjectAccessor.Create(source);
if (sourceAccessor.Target.GetType().GetInterface(nameof(ICollection)) != null || sourceAccessor.Target.GetType().GetInterface(nameof(IEnumerable)) != null)
{
foreach (/* idk */)
{
// READ & RETURN VALUES HERE
}
}
An object could look like this:
{
Id: 1,
Surname: Doe,
Prename: John,
Professions: [
{ Name: ab },
{ Name: xy }
]
}
Which means professions would result in a problem.
Any advise how I can solve this problem? Thanks!
It's not obvious from the question what the data type of the source variable is, but you should just be able to check if the value returned by the accessor implements IEnumerable or not and act accordingly.
Here's a quick worked example that iterates over the Professions property of a 'Person' object and just dumps the ToString() representation to the console - if you wanted to dive into each Profession object using FastMember you could construct another ObjectAccessor to do it, I guess - it's not clear what your goal is once you're iterating.
The same tactic will work if you're building the ObjectAccessor directly from an array - you just check if the accessor.Target is IEnumerable and cast-and-iterate in a similar fashion.
class Program
{
static void Main(string[] args)
{
var p = new Person
{
Professions = new List<Profession>
{
new Profession("Joker"),
new Profession("Smoker"),
new Profession("Midnight toker")
}
};
var accessor = ObjectAccessor.Create(p);
var professions = accessor[nameof(Person.Professions)];
if (professions is IEnumerable)
{
foreach (var profession in (IEnumerable)professions)
{
Console.WriteLine(profession);
}
}
}
}
class Person
{
public List<Profession> Professions { get; set; }
}
class Profession
{
public string Name { get; set; }
public Profession( string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
Related
Consider the following mutable object:
class SomePoco
{
public int Id{get;set;}
public string Name{get;set;}
}
Let's round trip it through Json.NET:
var p=new SomePoco{Id=4,Name="spender"};
var json=JsonConvert.SerializeObject(p);
var pr = JsonConvert.DeserializeObject<SomePoco>(json);
Console.WriteLine($"Id:{pr.Id}, Name:{pr.Name}");
All is good.
Now, let's make out POCO immutable and feed values via a constructor:
class SomeImmutablePoco
{
public SomeImmutablePoco(int id, string name)
{
Id = id;
Name = name;
}
public int Id{get;}
public string Name{get;}
}
... and round-trip the data again:
var p = new SomeImmutablePoco(5, "spender's immutable friend");
var json = JsonConvert.SerializeObject(p);
var pr = JsonConvert.DeserializeObject<SomeImmutablePoco>(json);
Console.WriteLine($"Id:{pr.Id}, Name:{pr.Name}");
Still good.
Now, let's make a small change to our immutable class by renaming a constructor parameter:
class SomeImmutablePoco
{
public SomeImmutablePoco(int pocoId, string name)
{
Id = pocoId;
Name = name;
}
public int Id{get;}
public string Name{get;}
}
then:
var p = new SomeImmutablePoco(666, "diabolo");
var json = JsonConvert.SerializeObject(p);
var pr = JsonConvert.DeserializeObject<SomeImmutablePoco>(json);
Console.WriteLine($"Id:{pr.Id}, Name:{pr.Name}");
Oh dear... It looks like Json.NET is doing some reflective magic over the names of our constructor parameters and matching them to property names in our POCO/json. This means that our freshly deserialized object doesn't get an Id assigned to it. When we print out the Id, it's 0.
This is bad, and particularly troublesome to track down.
This problem might exist in a large collection of POCOs. How can I automate finding these problem POCO classes?
Here is the code that finds such classes using reflection:
var types = new List<Type>() { typeof(SomeImmutablePoco) }; // get all types using reflection
foreach (var type in types)
{
var props = type.GetProperties(bindingAttr: System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var ctor in type.GetConstructors())
{
foreach (var param in ctor.GetParameters())
{
if (!props.Select(prop => prop.Name.ToLower()).Contains(param.Name.ToLower()))
{
Console.WriteLine($"The type {type.FullName} may have problems with Deserialization");
}
}
}
}
You can map your json property like that:
class SomeImmutablePoco
{
public SomeImmutablePoco(int pocoId, string name)
{
Id = pocoId;
Name = name;
}
[JsonProperty("pocoId")]
public int Id { get; }
public string Name { get; }
}
I have two lists of the same object and I want to find the Union and Intersection of these lists based on a case-insensitive comparison of a property of the object.
For simplicity, let's call it a Person, and I want to filter on the Person.Name property.
What is the recommended way to do this? I'm hoping to keep the code in a single line of Linq.
Currently I'm doing the following:
public class Person { public string Name { get; set; } }
-
var people =
firstListOfPeople.Where(
p1 => p1.Name != null &&
secondListOfPeople
.Where(p2 => p2.Name != null)
.Select(p2 => p2.Name.ToUpper())
.Contains(p1.Name.ToUpper()));
You can collapse your code down to this:
firstListOfPeople.Intersect(secondListOfPeople);
The catch comes with the case-insensitive compare of the name. Intersect uses the default equality comparer (reference equality), so you need to implement IEqualityComparer<T> (MSDN).
That comparison would do the name based comparison. You would then create one and pass it to the correct overload of Intersect: http://msdn.microsoft.com/en-us/library/vstudio/bb355408(v=vs.100).aspx
firstListOfPeople.Instersect(secondListOfPeople, myComparer);
I think #BradleyDotNET has the right answer, but since I already had an example mostly complete, I thought I'd post it in case it helps someone down the road:
void Main()
{
var firstListOfPeople = new[]
{
new Person { Name = "Rufus" },
new Person { Name = "Bob" },
new Person { Name = "steve" },
};
var secondListOfPeople = new[]
{
new Person { Name = "john" },
new Person { Name = "Bob" },
new Person { Name = "rufus" },
};
var people = firstListOfPeople.Intersect(secondListOfPeople, new PersonNameComparer());
people.Dump(); // displays the result if you are using LINQPad
}
public class Person
{
public string Name { get; set; }
}
public class PersonNameComparer: EqualityComparer<Person>
{
public override bool Equals(Person p1, Person p2)
{
return p1.Name.Equals(p2.Name, StringComparison.OrdinalIgnoreCase);
}
public override int GetHashCode(Person p)
{
return p.Name.ToLower().GetHashCode();
}
}
Say I have the following (simplified):
public class Item
{
public String Name { get; set; }
public String Type { get; set; }
}
public class Armor : Item
{
public int AC { get; set; }
public Armor () { Type = "Armor"; }
}
public class Weapon : Item
{
public int Damage { get; set; }
public Armor () { Type = "Weapon"; }
}
public class Actor
{
...
}
public class HasItem : Relationship<ItemProps>, IRelationshipAllowingSourceNode<Actor>, IRelationshipAllowingTargetNode<Item>
{
public readonly string TypeKey = "HasItem";
public HasItem ( NodeReference targetItem, int count = 1 )
: base(targetItem, new ItemProps { Count = count })
{
}
public override string RelationshipTypeKey
{
get { return TypeKey; }
}
}
With this setup I can easily create a heterogeneous list of Weapons, Armor, etc related to the Actor. But I can't seem to figure out how to get them out. I have this method (again simplified) to get a list of all the related items, but it gets them all out as Items. I can't figure out how to get them as their actual type. I can use the Type field to determine the type, but there doesn't seem to be anyway of dynamically building the return:
public IEnumerable<Item> Items
{
get
{
return
GameNode
.GraphClient
.Cypher
.Start(new { a = Node.ByIndexLookup("node_auto_index", "Name", Name) })
.Match("(a)-[r:HasItem]-(i)")
.Return<Item>("i") // Need something here to return Armor, Weapon, etc as needed based on the Type property
.Results;
}
}
I found a bad workaround where I return the Type and NodeID and run the list through a switch statement that does a .Get with the NodeID and casts it to the right type. but this is inflexible and inefficient. I could run one query for each derived class and concatenate them together, but the thought of that makes my skin crawl.
This seems like it would be a common problem, but I couldn't find anything online. Any ideas?
The problem is how the data is stored in Neo4J, and serialized back via Json.net.
Let's say I have a sword:
var sword = new Weapon{
Name = "Sword 12.32.rc1",
Type = "Sword"
Damage = 12
};
If I serialize this to neo4j: graphClient.Create(sword); all is fine, internally we now have a Json representation which will look something like this:
{ "Name" : "Sword 12.32.rc1", "Type": "Sword", "Damage": "12"}
There is no information here that the computer can use to derive that this is in fact of type 'Sword', so if you bring back a collection of type Item it can only bring back the two properties Name and Type.
So, there are two solutions that I can think of, neither one of which is great, but both do get you with a one query solution. The first (most sucky) is to create a 'SuperItem' which has all the properties from the derived classes together, so:
public class SuperItem { Name, Type, Damage, AC } //ETC
But that is horrible, and kind of makes having a hierarchy pointless. The 2nd option, which whilst not great is better - is to use a Dictionary to get the data:
var query = GraphClient
.Cypher
.Start(new {n = actorRef})
.Match("n-[:HasItem]->item")
.Return(
item => new
{
Item = item.CollectAs<Dictionary<string,string>>()
});
var results = query.Results.ToList();
Which if you run:
foreach (var data in results2.SelectMany(item => item.Item, (item, node) => new {item, node}).SelectMany(#t => #t.node.Data))
Console.WriteLine("Key: {0}, Value: {1}", data.Key, data.Value);
Would print out:
Key: Type, Value: Sword
Key: Damage, Value: 12
Key: Name, Value: 12.32.rc1
So, now we have a dictionary of the properties, we can create an extension class to parse it:
public static class DictionaryExtensions
{
public static Item GetItem(this Dictionary<string, string> dictionary)
{
var type = dictionary.GetTypeOfItem().ToLowerInvariant();
var json = dictionary.ToJson();
switch (type)
{
case "sword":
return GetItem<Weapon>(json);
case "armor":
return GetItem<Armor>(json);
default:
throw new ArgumentOutOfRangeException("dictionary", type, string.Format("Unknown type: {0}", type));
}
}
private static string GetTypeOfItem(this Dictionary<string, string> dictionary)
{
if(!dictionary.ContainsKey("Type"))
throw new ArgumentException("Not valid type!");
return dictionary["Type"];
}
private static string ToJson(this Dictionary<string, string> dictionary)
{
var output = new StringBuilder("{");
foreach (var property in dictionary.OrderBy(k => k.Key))
output.AppendFormat("\"{0}\":\"{1}\",", property.Key, property.Value);
output.Append("}");
return output.ToString();
}
private static Item GetItem<TItem>(string json) where TItem: Item
{
return JsonConvert.DeserializeObject<TItem>(json);
}
}
and use something like:
var items = new List<Item>();
foreach (var data in results)
foreach (Node<Dictionary<string, string>> item in data.Item)
items.Add(item.Data.GetItem());
Where items will be the types you're after.
I know this isn't great, but it does get you to one query.
I am not sure what the best and simplest way to do this, so any advice is appreciated.
I want to get all the fields on any/all/single domain entity class and add prefix/remove prefix dynamically when calling a particular method.
For example, I have entities such as:
public class Shop
{
public string TypeOfShop{get;set}
public string OwnerName {get;set}
public string Address {get;set}
}
public class Garage
{
public string Company {get;set}
public string Name {get;set}
public string Address {get;set}
}
and so on...
I want to get a list of the properties with a prefix:
public Class Simple
{
public class Prop
{
public string Name{get;set;}
public string Value{get;set;}
}
public ICollection list = new List<Prop>();
//set all prop
public void GetPropertiesWithPrefix(Garage mygarage, string prefix)
{
list.Add(new Prop{Name = prefix + "_Company", Value = mygarage.Company});
//so on... upto 50 props...
}
}
//to get this list I can simple call the list property on the Simple class
When reading each field I am using a switch statement and setting the value.
//Note I return a collection of Prop that have new values set within the view,lets say
//this is a result returned from a controller with the existing prop names and new values...
public MyGarage SetValuesForGarage(MyGarage mygarage, string prefix, ICollection<Prop> _props)
{
foreach (var item in _prop)
{
switch(item.Name)
{
case prefix + "Company":
mygarage.Company = item.Value;
break;
//so on for each property...
}
}
}
Is there a better, simpler or more elegant way to do this with linq or otherwise?
You could store props in a dictionary, then have:
mygarage.Company = _props[prefix + "_Company"];
mygarage.Address = _props[prefix + "_Address"];
//And so on...
in your SetValuesForGarage method instead of a loop with a switch inside.
EDIT
For more info on using Dictionary see MSDN.
You can define list something like:
Dictionary<string, string> list = new Dictionary<string, string>();
And have something like the following in your GetPropertiesWithPrefix method:
list.Add(prefix + "_Company", mygarage.Company);
list.Add(prefix + "_Address", mygarage.Address);
//And so on...
This would eliminate your Prop class.
Maybe the following method works for you. It takes any object, looks up its properties and returns a list with your Prop objects, each for every property.
public class PropertyReader
{
public static List<Prop> GetPropertiesWithPrefix(object obj, string prefix)
{
if (obj == null)
{
return new List<Prop>();
}
var allProps = from propInfo
in obj.GetType().GetProperties()
select new Prop()
{
Name = prefix + propInfo.Name,
Value = propInfo.GetValue(obj, null) as string
};
return allProps.ToList();
}
}
How do I find and replace a property using Linq in this specific scenario below:
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
//TODO: Just copying values... Find out how to find the index and replace the value
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
Thanks for helping out in advance.
Do not use LINQ because it will not improve the code because LINQ is designed to query collection and not to modify them. I suggest the following.
// Just realized that Array.IndexOf() is a static method unlike
// List.IndexOf() that is an instance method.
Int32 index = Array.IndexOf(this.Properties, name);
if (index != -1)
{
this.Properties[index] = value;
}
else
{
throw new ArgumentOutOfRangeException();
}
Why are Array.Sort() and Array.IndexOf() methods static?
Further I suggest not to use an array. Consider using IDictionary<String, Property>. This simplifies the code to the following.
this.Properties[name] = value;
Note that neither solution is thread safe.
An ad hoc LINQ solution - you see, you should not use it because the whole array will be replaced with a new one.
this.Properties = Enumerable.Union(
this.Properties.Where(p => p.Name != name),
Enumerable.Repeat(value, 1)).
ToArray();
[note: this answer was due to a misunderstanding of the question - see the comments on this answer. Apparently, I'm a little dense :(]
Is your 'Property' a class or a struct?
This test passes for me:
public class Property
{
public string Name { get; set; }
public string Value { get; set; }
}
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
public Property[] Properties { get; set; }
public Property this[string name]
{
get { return Properties.Where((e) => e.Name == name).Single(); }
set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
}
}
[TestMethod]
public void TestMethod1()
{
var pb = new PropertyBag() { Properties = new Property[] { new Property { Name = "X", Value = "Y" } } };
Assert.AreEqual("Y", pb["X"].Value);
pb["X"] = new Property { Name = "X", Value = "Z" };
Assert.AreEqual("Z", pb["X"].Value);
}
I have to wonder why the getter returns a 'Property' instead of whatever datatype .Value, but I'm still curious why you're seeing a different result than what I am.