Trying to define method similar to List<T>.ConvertAll(TOutput) - c#

I want to define an extension method of List<T> called MergeAll(). I want it to take in elements from a list of one type and produce a list of another. I have a delegate defined for the Merger (equivalent of Converter)
public delegate TOutput Merger<in TInput, out TOutput>(TInput input)
but cannot for the life of me figure out the syntax of the extension method. My attempt is:
public static List<TOutput> MergeAll<TOutput>(this List<TOutput> output,
Merger<TOutput, TInput> merger)
Then, what should the body of MergeAll look like?

What you're attempting is called a projection.
An extension method is already included in the .NET Framework to achieve this. IEnumerable.Select, and you can use it in the fashion below.
void Main()
{
List<Foo> foos = new List<Foo>
{
new Foo { Name = "Fu" },
new Foo { Name = "Foe" },
new Foo { Name = "Thumb" }
};
IEnumerable<Bar> bars = foos.Select(foo => new Bar
{
BarId = foo.Id,
Name = foo.Name
});
}
public class Foo
{
public Foo() { Id = Guid.NewGuid().ToString(); }
public string Id { get; set; }
public string Name { get; set; }
}
public class Bar
{
public Bar()
{
this.BarId = Guid.NewGuid().ToString();
this.TimeCreated = DateTime.UtcNow;
}
public string BarId { get; set; }
public string Name { get; set; }
public DateTime TimeCreated { get; set; }
}
How it's implemented....
If you wanted to implement a custom solution yourself for the sake of learning, this is how you would go about doing it:
public static class Extensions
{
public static IEnumerable<TDestination> ConvertTo<TFrom, TDestination>(this IEnumerable<TFrom> fromCollection, Func<TFrom, TDestination> expression)
{
List<TDestination> destinationList = new List<TDestination>();
foreach (var element in fromCollection)
{
destinationList.Add(expression.Invoke(element));
}
return destinationList;
}
}
void Main()
{
List<Foo> foos = new List<Foo>
{
new Foo { Name = "Fu" },
new Foo { Name = "Foe" },
new Foo { Name = "Thumb" }
};
IEnumerable<Bar> customBars = foos.ConvertTo(foo => new Bar
{
BarId = foo.Id,
Name = foo.Name
});
}

You need to add TInput to MergeAll<TInput, TOutput> and to change the first parameter to be List<TInput> and the second to be Func<TInput, TOutput>.
public static List<TOutput> MergeAll<TInput, TOutput>(this List<TInput> inputs,
Func<TInput, TOutput> merger)
{
var outputs = new List<TOutput>();
foreach (var input in inputs)
{
outputs.Add(merger(input));
}
return outputs;
}
A simple usage that convert double to int will look like below:
List<double> doubles = new List<double> { 1.3, 2.2, 3.5, 4.7 };
List<int> ints = doubles.MergeAll(doubleParam => Convert.ToInt32(doubleParam)).ToList();

Related

How to check equivalence using Fluent Assertion Should().BeEquivalentTo() when using derived classes

I'm having problems trying to get Should().BeEquivalentTo() to work with types that derive from a base class and implement a collection interface:
public class Entity
{
public string Id {get; set;}
public string Name {get; set;}
}
public class Derived : Entity, ICollection<Entity>
{
private List<Entity> m_Children = new List<Entity>();
public string Description { get; set; }
public int Count => ((ICollection<Entity>)m_Children).Count;
public bool IsReadOnly => ((ICollection<Entity>)m_Children).IsReadOnly;
public void Add(Entity item)
{
((ICollection<Entity>)m_Children).Add(item);
}
public void Clear()
{
((ICollection<Entity>)m_Children).Clear();
}
public bool Contains(Entity item)
{
return ((ICollection<Entity>)m_Children).Contains(item);
}
public void CopyTo(Entity[] array, int arrayIndex)
{
((ICollection<Entity>)m_Children).CopyTo(array, arrayIndex);
}
public IEnumerator<Entity> GetEnumerator()
{
return ((ICollection<Entity>)m_Children).GetEnumerator();
}
public bool Remove(Entity item)
{
return ((ICollection<Entity>)m_Children).Remove(item);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((ICollection<Entity>)m_Children).GetEnumerator();
}
}
The Test
[TestMethod]
public void EquivalenceTest()
{
var expected = new Derived
{
Id = "123",
Name = "abc",
Description = "def"
};
var actual = new Derived
{
Id = "121",
Name = "xyz",
Description = "def"
};
actual.Should().BeEquivalentTo(expected); // This succeeds, but should fail
}
The call to BeEquivalentTo seems to be ignoring the properties that are defined in the object, and only treating the object as a collection.
How can I get the framework to check the properties and the contents of the collection?
Edit
It seems like this is a known issue
Does anyone know of a workaround?
It's a known issue when comparing classes that implements IEnumerable and have extra properties to be compared.
Here's a way to hack the comparison.
public class Entity : IEnumerable<int>
{
private int[] ints = new[] { 1 };
public int Id { get; set; }
public string Name { get; set; }
public IEnumerator<int> GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
}
[TestMethod]
public void EquivalenceTest()
{
var expected = new Entity
{
Id = 1,
Name = "abc",
};
var actual = new Entity
{
Id = 1,
Name = "abc",
};
actual.Should().BeEquivalentTo(expected, opt => opt
.Using<Entity>(e =>
e.Subject.Should().Match<Entity>(f => f.Name == e.Expectation.Name)
.And.Subject.Should().Match<Entity>(f => f.Id == e.Expectation.Id)
.And.Subject.Should().BeEquivalentTo(e.Expectation)
)
.WhenTypeIs<Entity>());
}

Saving item picked from list

Main class:
public class Main
{
private string param;
public Main(string param) { this.param = param; }
public List<Foo> Foos
{
get {return GetFoos();}
// add functionality of saving Foo (single item, not the whole list) here?
}
private List<Foo> GetFoos()
{
List<Foo> x = new List<Foo>();
return x;
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
// or maybe here?
}
}
Test class:
public class Test
{
public Test()
{
var main = new Main("hi!");
// usage 1
main.Foos.Find(p => p.Id == 1).Save(); // method visible here
var foo = new Main.Foo();
// usage 2
foo.Save(); // method not visible here
}
}
Comments in the code basically say everything:
1. I want to implement the Save() method of the object Foo.
2. Method can be called only if the Foo object is picked up from the list (usage 1).
3. Method can not be called from the Foo object created alone (usage 2).
4. Method must use private value of the property param passed during initialization of the main class.
You can use an interface to hide the method Save.
To do this, the Save method must be implemented explicitly.
Additionally you need a link to the main object. In your subclass Foo you can access the private attribute from Main directly.
Interface:
public interface IFoo
{
int Id { get; set; }
string Name { get; set; }
void Save();
}
Class:
public class Main
{
private string param;
private List<IFoo> foos = new List<IFoo>();
public Main(string param) { this.param = param; }
public List<IFoo> Foos
{
get { return this.foos; }
}
public void AddFoo(int pnId, string pnName)
{
this.foos.Add(new Foo(this) { Id = pnId, Name = pnName });
}
public class Foo : IFoo
{
private Main moParent;
public Foo() { }
public Foo(Main poParent)
{
this.moParent = poParent;
}
public int Id { get; set; }
public string Name { get; set; }
//Implement interface explicitly
void IFoo.Save()
{
if (this.moParent == null)
throw new InvalidOperationException("Parent not set");
Console.WriteLine($"Save with Param: {this.moParent.param}, Id: {this.Id} Name: {this.Name}");
//Save Item
}
}
}
Usage:
var main = new Main("hi!");
main.AddFoo(1, "Foo1");
// usage 1
main.Foos.Find(p => p.Id == 1).Save(); // method visible here
var foo = new Main.Foo();
// usage 2
//foo.Save(); // Save is not visible here

Get list of properties in LINQ projection

I have a following LINQ expression:
var query = entities
.Select(e => new MyObject()
{
Property1 = e.Item1,
Property2 = e.Item2
});
MyObject might have also Property3, Property4 defined. I need to realize which properties are part of LINQ projection via expression visitor.
So I call something like:
var listOfProperties = query.GetSelectedPropertyNames();
and the content of listOfProperties will be string array which contains Property1, Property2 or something by which I can check:
var isPropertyInProjection = query.HasPropertyInProjection(nameof(MyObject.Property3));
and the result will be false.
You can easily do that using an ExpressionVisitor. Just create a new class and override the visiting methods. If you know that the projection was done using member bindings, you can simply override the method VisitMemberBinding and add the bound member to a list that you store as an instance variable. Then all you need to do is to make that instance variable public.
class ProjectionAnalyzer : ExpressionVisitor
{
private HashSet<MemberInfo> boundMembers = new HashSet<MemberInfo>();
protected override MemberBinding VisitMemberBinding(MemberBinding node)
{
boundMembers.Add(node.Member);
return base.VisitMemberBinding(node);
}
public IEnumerable<MemberInfo> BoundMembers => boundMembers;
}
Then, use this class as follows:
var analyzer = new ProjectionAnalyzer();
analyzer.Visit(selectorPredicate);
var boundMembers = analyzer.BoundMembers;
How you obtain the selector predicate depends on your LINQ provider.
I did something similar using VisitMemberAssignment:
namespace BoundPropertiesinQuery
{
static class IEnumerableExtensions
{
class ProjectedVisitor : ExpressionVisitor
{
public IList<string> ProjectedPropertyNames { get; set; } = new List<string>();
protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
{
ProjectedPropertyNames.Add(node.Member.Name);
return base.VisitMemberAssignment(node);
}
}
public static IEnumerable<string> ProjectedProperties<T>(this IQueryable<T> #this)
{
var pv = new ProjectedVisitor();
pv.Visit(#this.Expression);
return pv.ProjectedPropertyNames.Distinct();
}
}
internal class MyObject
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public int Property3 { get; set; }
public int Property4 { get; set; }
}
internal class MyOtherObject
{
public int other1 { get; set; }
public int other2 { get; set; }
public int other3 { get; set; }
public int other4 { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
var listOfItems = new List<MyOtherObject>()
{
new MyOtherObject
{
other1 = 1,
other2 = 2,
other3 = 3,
other4 = 4
},
new MyOtherObject
{
other1 = 5,
other2 = 6,
other3 = 7,
other4 = 8
}
};
var result = listOfItems.AsQueryable().Select(m => new MyObject
{
Property1 = m.other1,
Property2 = m.other2
}).ProjectedProperties();
foreach (var item in result)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
}
}

Generic query in Linq

I want to make a generic search UserControl in wpf. I want it to get a collection of objects and a name of a property to search by.
The problem is I can't use generics because the code that calls the search function also can't know of the type.
Is there a way to achieve this? Or some way to query an Object that is underneath another type?
Consider this example.
interface IFoo
{
}
class Bar1 : IFoo
{
//interface implementations
public string Property1 { get; set; }
public string myProperty1 { set; get; }
}
class Bar2 : IFoo
{
//interface implementations
public string Property1 { get; set; }
public string myProperty1 { set; get; }
}
//Search the list of objects and access the original values.
List<IFoo> foos = new List<IFoo>();
foos.Add(new Bar1
{
Property1 = "bar1",
myProperty1 ="myBar1"
});
foos.Add(new Bar1());
foos.Add(new Bar2());
foos.Add(new Bar2());
//Get the objects.
foreach (var foo in foos)
{
//you can access foo directly without knowing the original class.
var fooProperty = foo.Property1;
//you have to use reflection to get the original type and its properties and methods
Type type = foo.GetType();
foreach (var propertyInfo in type.GetProperties())
{
var propName = propertyInfo.Name;
var propValue = propertyInfo.GetValue(foo);
}
}
var result = list.Where(a => a.propertyName);
You can use reflection
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var Data = new List<object>() { new A() { MyProperty = "abc" }, new B() { MyProperty = "cde"} };
var Result = Data.Where(d => (d.GetType().GetProperty("MyProperty").GetValue(d) as string).Equals("abc"));
// Result is IEnumerable<object> wich contains one A class object ;)
}
}
class A
{
public string MyProperty { get; set; }
}
class B
{
public string MyProperty { get; set; }
}
}

Calling a function based on parameter type

I am trying to figure out how to simplify the following
let's say I have 2 entity classes
public class A
{
public int Id { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
AND
public class B
{
public int Id { get; set; }
public string Nom { get; set; }
public string Ville { get; set; }
}
classes that are similar, but not the same.
each class has a repository classes it uses for CRUD Operations, for example...
public class RepA
{
public static List<A> GetAll()
{
List<A> list = new List<A>();
A a1 = new A() {Id=1, Name="First A", City="Boston"};
A a2 = new A() {Id=2, Name="First B", City="Chicago"};
A a3 = new A() {Id=3, Name="First C", City="San Francisco"};
list.Add(a1);
list.Add(a2);
list.Add(a3);
return list;
}
public static void SaveAll(List<A> list)
{
foreach (A a in list)
{
Console.WriteLine("Saved Id = {0} Name = {1} City={2}",
a.Id, a.Name, a.City);
}
}
}
AND
public class RepB
{
public static List<B> GetAll()
{
List<B> list = new List<B>();
B b1 = new B() {Id=1, Nom="Second A", Ville="Montreal"};
B b2 = new B() {Id=2, Nom="Second B", Ville="Paris"};
B b3 = new B() {Id=3, Nom="Second C", Ville="New Orleans"};
list.Add(b1);
list.Add(b2);
list.Add(b3);
return list;
}
public static void SaveAll(List<B> list)
{
foreach (B b in list)
{
Console.WriteLine("Saved Id = {0} Name = {1} City={2}", b.Id,
b.Nom, b.Ville);
}
}
}
How would I go about making anonymous call to my repository without having to resort to this, because in my real world example, i have 100 repositories, and not 2.
void Main()
{
ChosenType chosentype = RandomChosenType(); //A or B
switch (chosentype)
{
case ChosenType.A:
var listA = RepA.GetAll();
RepA.SaveAll(listA);
break;
case ChosenType.B:
var listB = RepB.GetAll();
RepB.SaveAll(listB);
break;
default:
break;
}
}
Make a base class or use an interface:
public interface IBase<T>
{
List<T> GetAll();
void SaveAll(List<T> items);
}
public class RepA : IBase<RepA>
{
public List<RepA> GetAll() { return new List<RepA>(); }
public void SaveAll(List<RepA> repA) { }
}
public class RepB : IBase<RepB>
{
public List<RepB> GetAll() { return new List<RepB>(); }
public void SaveAll(List<RepB> repB) { }
}
void Main()
{
IBase chosenType = RandomChosenType();
var list = chosenType.GetAll();
}
You should use a single generic repository. The operations should be handled by injected delegates. A repository could look like this:
public class GenericRepositoryExample
{
public void Save<T>(IList<T> persons, SaveDelegate<T> save)
{
foreach (T person in persons)
{
Console.WriteLine(save(person));
}
}
}
Note that the save delegate is passed to the Save method. The SaveDelegate in your example could be declared as:
public delegate string SaveDelegate<T>(T input);
For ease, I have created a HelperClass containing the delegated functions. In real life helper classes should generally be avoided if possible.
public static class HelperClass
{
public static string FrenchSave(B frenchInput)
{
string result = string.Format("ID = {0}; Name = {1}; City = {2}", frenchInput.Id, frenchInput.Nom, frenchInput.ville);
return result;
}
public static string EnglishSave(A englishInput)
{
string result = string.Format("ID = {0}; Name = {1}; City = {2}", englishInput.Id, englishInput.name, englishInput.city);
return result;
}
}
To illustrate the use of this setup, I have created the following unit test:
[Test]
public void TestGenericRepository()
{
IList<A> aList = new List<A>();
aList.Add(new A() { Id = 1, name = "George", city = "Chicago"});
aList.Add(new A() { Id = 2, name = "Bill", city = "Toledo" });
List<B> bList = new List<B>();
bList.Add(new B() {Id= 1, Nom = "Nathalie", ville = "Paris"});
bList.Add(new B() {Id = 2, Nom = "Michelle", ville = "Lyon"});
GenericRepositoryExample repository = new GenericRepositoryExample();
repository.Save<A>(aList,HelperClass.EnglishSave);
repository.Save<B>(bList,HelperClass.FrenchSave);
}
You can make your repositories implement an interface, say IGetAllSaveAll. Then you can store your repositories in a list, and cast them to that interface. That way you'll be able to call the GetAll function on all of them:
(actually the first interface isn't mandatory, you could directly write it as IEnumerable<object> GetAll()...)
interface IGetAllSaveAll<T>
{
IEnumerable<T> GetAll();
void SaveAll(IEnumerable<T> obj);
}
you'll need to have a base interface:
interface IGetAllSaveAll : IGetAllSaveAll<object>
and to use it:
public class RepA: IGetAllSaveAll
public class RepB: IGetAllSaveAll
....
Then you can keep a dictionnary of all these repositories somewhere:
Dictionnary<Type, IGetAllSaveAll> myDic;
Of course you'll still have to add your repositories to your dictionnary:
myDic.Add(typeof(A), new RepA());
And then to call it:
Type t = RandomChosenType();
myDic[t].GetAll();
The code you posted uses static methods. In order to implement an interface, you will need instance methods. Unless you want to use reflection (should be avoided in my opinion), these methods need to be ignorant of the type. Something like this:
public interface IRepository {
IEnumerable<object> GetAll();
}
And in RepA:
IEnumerable<object> IRepository.GetAll() {
return RepA.GetAll();
}
Instead of storing types, each of your menu selections can just contain an instance of the appropriate repository class in a field of type IRepository. After calling GetAll on one of the instances, you can later cast the result to the specific type (like List<A>) if necessary.
Try this approach based on reflection and some assumptions about your classes' structures:
static void Main(string[] args)
{
var types = Assembly.GetExecutingAssembly().Modules
.SelectMany(m => m.GetTypes())
.Where(t =>
t.GetMethod("GetAll") != null &&
t.GetMethod("SaveAll") != null &&
t.GetMethod("GetAll").ReturnType.IsGenericType)
.Select(t =>
new
{
RepositoryType = t,
ReturnTypeArgument =
t.GetMethod("GetAll").ReturnType.GenericTypeArguments[0]
}
)
.ToList();
(new List<dynamic> { new A(), new B() }).ToList().ForEach(chosenType =>
{
var association = types
.FirstOrDefault(t =>
t.ReturnTypeArgument == chosenType.GetType());
if (association == null)
return;
var repType = association.RepositoryType;
dynamic list = repType.GetMethod("GetAll")
.Invoke(chosenType, new object[] { });
repType.GetMethod("SaveAll")
.Invoke(chosenType, new object[] { list });
});
}
Given your exact scenario, where you've got an enum representing each of the possible data types, here's something that may work.
Map each enum value to a repository type using an attribute. Each repository inherits from a generic class, which implements a basic interface which is not strongly typed. The repo methods change from static to instance members. The base repo class has to do casting to cast object to the appropriate type and back, but the actual repository implementations are strongly typed.
You can take this a step further and try to cache some of the reflection using expression trees so you only have to do it once, but it depends on how optimized you really need to make it.
public enum ChosenType {
[Repo(typeof(RepA))] A = 0,
[Repo(typeof(RepB))] B = 1
}
public class RepoAttribute : Attribute {
public RepoAttribute(Type repoType) { RepoType = repoType; }
public Type RepoType { get; set; }
}
class Program
{
static void Main()
{
ChosenType chosentype = RandomChosenType(); //A or B
// Make an instance of the appropriate repo based on the mapping
// to the enum value.
// This is a moderately expensive call, and there's room for improvement
// by using expression trees and caching lambda expressions.
var repo = (IRepo)Activator.CreateInstance(
((RepoAttribute)typeof(ChosenType).GetMember(chosentype.ToString())
.Single().GetCustomAttributes(typeof(RepoAttribute), false).Single()
).RepoType);
var list = repo.GetAll();
repo.SaveAll(list);
Console.Read();
}
static Random _rand = new Random();
static ChosenType RandomChosenType()
{
return (ChosenType)_rand.Next(0, 2);
}
}
public class A { /* No change */ }
public class B { /* No change */ }
public interface IRepo {
List<object> GetAll();
void SaveAll(List<object> list);
}
public abstract class Repo<T> : IRepo {
List<object> IRepo.GetAll() {
return GetAll().Cast<object>().ToList();
}
void IRepo.SaveAll(List<object> list) {
SaveAll(list.Cast<T>().ToList());
}
public abstract List<T> GetAll();
public abstract void SaveAll(List<T> list);
}
public class RepA : Repo<A> {
public override List<A> GetAll() { /* No change except the signature */ }
public override void SaveAll(List<A> list) { /* No change except the signature */ }
}
public class RepB : Repo<B> {
public override List<B> GetAll() { /* No change except the signature */ }
public override void SaveAll(List<B> list) { /* No change except the signature */ }
}

Categories