how to generic Automapper Config - c#

I use Automapper version 4.2.0 and I all Action Methods I have setting Like this :
var attributeGroups = _attributeGroupService.AttributeGroupDropdown();
var mapconfiguration = new MapperConfiguration(cfg => cfg.CreateMap<AttributeGroup, AttributeGroupViewModel>());
var mapper = mapconfiguration.CreateMapper();
var result = mapper.Map(attributeGroups, new List<AttributeGroupViewModel>());
I dont repeat this codes in all actions , I want create a generic method and just pass data to it and map it ,to do this , I create a Method like this ?
public N mapping<T,K,M,N>(T resource, K destination,M model,N newModel)
{
var mapconfiguration = new MapperConfiguration(cfg => cfg.CreateMap<T, K>());
var mapper = mapconfiguration.CreateMapper();
var result = mapper.Map<M,N>(model, newModel);
return result;
}
and call it like this :
var ResultTest=mapping<AttributeGroup,AttributeGroupViewModel,attributeGroups,new List<AttributeGroupViewModel>()>();
but it doesnt complie .
how can I do it?

Short answer: you need to provide types in the generic parameter list and variables in the argument list of your function call. Also, you don't need the T resource, K destination arguments at all, since they are unused.
There is another problem with your approach, since using it is not really convenient. So I suggest that you provide two specialized methods with reduced complexity.
See the below complete example. It contains the method mapAnything<...>, which is a working equivalent to your mapping<...> method. The methods mapObject<...> and mapCollection<...> are the specialized methods I was talking about.
class TestResource
{
public int Testnumber { get; set; }
public string Testtext { get; set; }
}
class TestDestination
{
public string Testtext { get; set; }
}
class Program
{
// equivalent to what you tried to do - needs explicit generic parameters on call
static N mapAnything<T, K, M, N>(M model, N newModel)
{
var mapconfiguration = new MapperConfiguration(cfg => cfg.CreateMap<T, K>());
var mapper = mapconfiguration.CreateMapper();
var result = mapper.Map<M, N>(model, newModel);
return result;
}
// variant for object mapping, where generics can be implicitely inferred
static N mapObject<M, N>(M model, N newModel)
{
var mapconfiguration = new MapperConfiguration(cfg => cfg.CreateMap<M, N>());
var mapper = mapconfiguration.CreateMapper();
var result = mapper.Map<M, N>(model, newModel);
return result;
}
// variant for lists, where generics can be implicitely inferred
static ICollection<N> mapCollection<M, N>(IEnumerable<M> model, ICollection<N> newModel)
{
var mapconfiguration = new MapperConfiguration(cfg => cfg.CreateMap<M, N>());
var mapper = mapconfiguration.CreateMapper();
var result = mapper.Map<IEnumerable<M>, ICollection<N>>(model, newModel);
return result;
}
static void Main(string[] args)
{
var res1 = new TestResource() { Testnumber = 1, Testtext = "a" };
var res2 = new List<TestResource>();
for (int i = 0; i < 10; i++)
{
res2.Add(new TestResource() { Testnumber = i, Testtext = "test: " + i });
}
var mapped1 = mapObject(res1, new TestDestination());
var mapped2 = mapCollection(res2, new HashSet<TestDestination>());
var mapped3 = mapAnything<TestResource, TestDestination, TestResource, TestDestination>(res1, new TestDestination());
var mapped4 = mapAnything<TestResource, TestDestination, IEnumerable<TestResource>, List<TestDestination>>(res2, new List<TestDestination>());
}
}

Related

Initializing (Entity) object by calling (get) property dynamically. Entity Framework , c#, ASP>NET

I have below piece of code:
public void DBMamLookup(int custid)
{
using (LookUpEntities1 lookUp = new LookUpEntities1())
{
var mamconfig = lookUp.MamConfigurations;
var userlookup = lookUp.UserAccount2_ISO2_3 ;
MamConfiguration obj = mamconfig.Where(m => m.CustID== custid).FirstOrDefault();
var objNN = lookUp.UserAccount2_ISO2_3.Where(m => m.CustID== custid).Take(15).ToList();
Type returnType;
switch (obj.ActiveTableName)
{
case "MamConfiguration":
returnType = typeof(MamConfiguration);
break;
case "UserAccount1_ISO1_1Billers":
returnType = typeof(UserAccount1_ISO2_3Billers);
break;
default:
returnType = typeof(UserAccount2_ISO2_3Billers);
break;
}
dynamic que3 = this.GetInstance<dynamic>(obj.ActiveTableName);
que3 = lookUp.Set(returnType);
for (int i = 0; i < que3.Local.Count; i++)
{
Console.WriteLine(que3.Local[i].UserAccount);
}
}
}
I have problem at below line in above code:
var objNN = lookUp.**UserAccount2_ISO2_3**.Where(m => m.CustID== custid).Take(15).ToList();
I have to make it dynamic and call the specific entity property at runtime. As I have property name in string i.e. obj.ActiveTableName how can I make a call something like below:
var objNN = lookUp.**[obj.ActiveTableName]**.Where(m => m.CustID== custid).Take(15).ToList();
First create an interface with common properties for all types:
For example:
interface IEntityWithCustID
{
int CustID { get; set; }
}
Make sure all relevant classes implement that interface
For example:
public class UserAccount2_ISO2_3 : IEntityWithCustID
Create a helper class to retrieve data
static class QueryHelper
{
public static List<IEntityWithCustID> GetResult(LookUpEntities1 lookup, string tableName, int custId)
{
var dbset = lookup.GetType().GetProperty(tableName).GetValue(lookup);
var entityType = dbset.GetType().GetGenericArguments()[0];
var method = typeof(QueryHelper).GetMethod(nameof(GetResultInternal)).MakeGenericMethod(entityType);
return (List<IEntityWithCustID>)method.Invoke(null, new object[] { dbset, custId });
}
public static List<IEntityWithCustID> GetResultInternal<T>(IDbSet<T> dbset, int custId) where T: class, IEntityWithCustID
{
return dbset.Where(m => m.CustID == custId).Take(15).ToList().Cast<IEntityWithCustID>().ToList();
}
}
Use that class from your code (For example)
var res = QueryHelper.GetResult(lookup, obj.ActiveTableName, custid);
There is another way where you can create Expression.Lambda to create custom lambda expression using Expression.Lambda call. It will be a little bit more complicated though.

how to Moq Fluent interface / chain methods

I'm using the moq framework by Daniel Cazzulino, kzu Version 4.10.1.
I want to moq so i can test a particular part of functionality (below is the simplistic version of the Code i could extract)
The fluent/chain method so are designed so you can get object by an Id and include any additional information if required.
i'm having some trouble fetching the correct object when the function is calling the moq'ed method, which is currently returning the last moq'ed object which is wrong
/*My current Moq setup*/
class Program
{
static void Main(string[] args)
{
var mock = new Mock<IFluent>();
var c1 = new ClassA() { Id = 1, Records = new List<int>() { 5, 2, 1, 10 }, MetaData = new List<string>() };
var c2 = new ClassA() { Id = 2, Records = new List<int>(), MetaData = new List<string>() { "X", "Y", "Z" } };
mock.Setup(x => x.GetById(1).IncludeRecords().IncludeMetaData().Get()).Returns (c1);
mock.Setup(x => x.GetById(2).IncludeRecords().IncludeMetaData().Get()).Returns(c2);
var result = new ComputeClass().ComputeStuff(mock.Object);
Console.WriteLine(result);
Console.ReadLine();
}
}
/*Fluent interface and object returned*/
public interface IFluent
{
IFluent GetById(int id);
IFluent IncludeRecords();
IFluent IncludeMetaData();
ClassA Get();
}
public class ClassA
{
public int Id { get; set; }
public ICollection<int> Records { get; set; }
public ICollection<string> MetaData { get; set; }
}
/*the method which is doing the work*/
public class ComputeClass
{
public string ComputeStuff(IFluent fluent)
{
var ids = new List<int>() { 1, 2 };
var result = new StringBuilder();
foreach (var id in ids)
{
var resClass = fluent.GetById(id).IncludeRecords().IncludeMetaData().Get();
result.Append($"Id : {id}, Records: {resClass.Records.Count}, MetaData: {resClass.MetaData.Count}{Environment.NewLine}");
}
return result.ToString();
}
}
Current incorrect result
/*Id : 1, Records: 0, MetaData: 3
Id : 2, Records: 0, MetaData: 3*/
Expected Result
/*Id : 1, Records: 3, MetaData: 0
Id : 2, Records: 0, MetaData: 3*/
The easiest way would be to split out each setup:
var mock = new Mock<IFluent>();
var mock1 = new Mock<IFluent>();
var mock2 = new Mock<IFluent>();
mock.Setup(x => x.GetById(1)).Returns(mock1.Object);
mock1.Setup(x => x.IncludeRecords()).Returns(mock1.Object);
mock1.Setup(x => x.IncludeMetaData()).Returns(mock1.Object);
mock1.Setup(x => x.Get()).Returns(c1);
mock.Setup(x => x.GetById(2)).Returns(mock2.Object);
mock2.Setup(x => x.IncludeRecords()).Returns(mock2.Object);
mock2.Setup(x => x.IncludeMetaData()).Returns(mock2.Object);
mock2.Setup(x => x.Get()).Returns(c2);
var result = new ComputeClass().ComputeStuff(mock.Object);
You could create an extension/utility to handle this all for you if you wanted something a bit more complex, take a look at this blog post: https://www.codemunki.es/2014/11/20/mocking-a-fluent-interface-automatically-in-moq/
Just an addition to the already existing answer. For mocking fluent API there is one usefull option within the moq, it is SetReturnsDefault, it could save some mocking especially if you have huge fluent API, e.g.
var mock = new Mock<IFluent>();
var mock1 = new Mock<IFluent>();
var mock2 = new Mock<IFluent>();
mock.Setup(x => x.GetById(1)).Returns(mock1.Object);
mock1.SetReturnsDefault(mock1.Object);
mock1.Setup(x => x.Get()).Returns(a);
mock.Setup(x => x.GetById(2)).Returns(mock2.Object);
mock2.SetReturnsDefault(mock2.Object);
mock2.Setup(x => x.Get()).Returns(b);
var aa = mock.Object.IncludeMetaData().GetById(1).IncludeMetaData().Get();
var bb = mock.Object.IncludeMetaData.GetById(2).IncludeMetaData.Get();
With this approach you actually have to mock only method which differ but not the all methods from fluent API.

RhinoMocks - Testing property values on reference types

I need to test logic that executes a function, after which it changes a property on the parameter and then executes the same function with the updated parameter.
To help illustrate this, here is some sample code:
Interface:
public interface IWorker
{
MyObjectB DoWork(MyObject myObject);
}
MyObjectB:
public class MyObjectB
{
public string Message { get; set; }
}
Implementation:
public MyObjectB DoWork(IWorker worker, MyObject myObject)
{
worker.DoWork(myObject);
myObject.Name = "PersonB";
worker.DoWork(myObject);
return new MyObjectB() { Message = "Done" };
}
Test:
public void RhinoMocksSampleTest()
{
var workerStub = MockRepository.GenerateStub<IWorker>();
workerStub.Stub(n => n.DoWork(Arg<MyObject>.Is.Anything));
var myObj = new MyObject { Id = 1, Name = "PersonA" };
var p = new Program();
p.DoWork(workerStub, myObj);
workerStub.AssertWasCalled(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonA")));
workerStub.AssertWasCalled(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonB")));
}
The first AssertWasCalled fails because the value is ‘PersonB’.
Is there a function/call I can use to test the state of the object for the first call?
Here's how I would do what you're trying to do:
public void RhinoMocksSampleTest()
{
var workerMock = MockRepository.GenerateMock<IWorker>();
workerMock.Expect(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonA")));
workerMock.Expect(d => d.DoWork(Arg<MyObject>.Matches(r => r.Name == "PersonB")));
var myObj = new MyObject { Id = 1, Name = "PersonA" };
var p = new Program();
p.DoWork(workerMock , myObj);
workerMock.VerifyAllExpectations();
}
In addition to nice answer what aprescott has provided I can show another one approach which could be useful in some situations:
The idea is to manually store values which you are interesting in into some collection. Then you will be able to assert that collection contains required sequense.
public void MyTest()
{
// that is list which will contain passed names
var actualNames = new List<string>();
// stub only saves passed Name property into list
var workerStub = MockRepository.GenerateStub<IWorker>();
workerStub
.Stub(w => w.DoWork(Arg<MyObject>.Is.Anything))
.Do((Action<MyObject>)(mo => actualNames.Add(mo.Name)));
var myObject = new MyObject { Name = "PersonA" };
var target = new MyWorker();
target.DoWork(workerStub, myObject);
// here we do assert that names list contains what is required
Assert.That(actualNames, Is.EqualTo(new[] { "PersonA", "PersonB" }));
}
PS. Yeah, it works for case when you need check that calls order is correct :)

Returning anonymous type in C#

I have a query that returns an anonymous type and the query is in a method. How do you write this:
public "TheAnonymousType" TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return "TheAnonymousType";
}
}
You can't.
You can only return object, or container of objects, e.g. IEnumerable<object>, IList<object>, etc.
You can return dynamic which will give you a runtime checked version of the anonymous type but only in .NET 4+
public dynamic Get() {
return new { Message = "Success" };
}
In C# 7 we can use tuples to accomplish this:
public List<(int SomeVariable, string AnotherVariable)> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB
.Select(s => (
SomeVariable = s.SomeVariable,
AnotherVariable = s.AnotherVariable))
.ToList();
}
}
You might need to install System.ValueTuple nuget package though.
You cannot return anonymous types. Can you create a model that can be returned? Otherwise, you must use an object.
Here is an article written by Jon Skeet on the subject
Code from the article:
using System;
static class GrottyHacks
{
internal static T Cast<T>(object target, T example)
{
return (T) target;
}
}
class CheesecakeFactory
{
static object CreateCheesecake()
{
return new { Fruit="Strawberry", Topping="Chocolate" };
}
static void Main()
{
object weaklyTyped = CreateCheesecake();
var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
new { Fruit="", Topping="" });
Console.WriteLine("Cheesecake: {0} ({1})",
stronglyTyped.Fruit, stronglyTyped.Topping);
}
}
Or, here is another similar article
Or, as others are commenting, you could use dynamic
You can use the Tuple class as a substitute for an anonymous types when returning is necessary:
Note: Tuple can have up to 8 parameters.
return Tuple.Create(variable1, variable2);
Or, for the example from the original post:
public List<Tuple<SomeType, AnotherType>> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select Tuple.Create(..., ...)
).ToList();
return TheQueryFromDB.ToList();
}
}
http://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx
C# compiler is a two phase compiler. In the first phase it just checks namespaces, class hierarchies, Method signatures etc. Method bodies are compiled only during the second phase.
Anonymous types are not determined until the method body is compiled.
So the compiler has no way of determining the return type of the method during the first phase.
That is the reason why anonymous types can not be used as return type.
As others have suggested if you are using .net 4.0 or grater, you can use Dynamic.
If I were you I would probably create a type and return that type from the method. That way it is easy for the future programmers who maintains your code and more readable.
Three options:
Option1:
public class TheRepresentativeType {
public ... SomeVariable {get;set;}
public ... AnotherVariable {get;set;}
}
public IEnumerable<TheRepresentativeType> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new TheRepresentativeType{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB;
}
}
Option 2:
public IEnumerable TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new TheRepresentativeType{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB;
}
}
you can iterate it as object
Option 3:
public IEnumerable<dynamic> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new TheRepresentativeType{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB; //You may need to call .Cast<dynamic>(), but I'm not sure
}
}
and you will be able to iterate it as a dynamic object and access their properties directly
Using C# 7.0 we still can't return anonymous types but we have a support of tuple types and thus we can return a collection of tuple (System.ValueTuple<T1,T2> in this case). Currently Tuple types are not supported in expression trees and you need to load data into memory.
The shortest version of the code you want may look like this:
public IEnumerable<(int SomeVariable, object AnotherVariable)> TheMethod()
{
...
return (from data in TheDC.Data
select new { data.SomeInt, data.SomeObject }).ToList()
.Select(data => (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject))
}
Or using the fluent Linq syntax:
return TheDC.Data
.Select(data => new {SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject})
.ToList();
.Select(data => (SomeVariable: data.SomeInt, AnotherVariable: data.SomeObject))
Using C# 7.1 we can omit properties names of tuple and they will be inferred from tuple initialization like it works with anonymous types:
select (data.SomeInt, data.SomeObject)
// or
Select(data => (data.SomeInt, data.SomeObject))
You can return list of objects in this case.
public List<object> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new { SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB ;
}
}
public List<SomeClass> TheMethod(SomeParameter)
{
using (MyDC TheDC = new MyDC())
{
var TheQueryFromDB = (....
select new SomeClass{ SomeVariable = ....,
AnotherVariable = ....}
).ToList();
return TheQueryFromDB.ToList();
}
}
public class SomeClass{
public string SomeVariable{get;set}
public string AnotherVariable{get;set;}
}
Creating your own class and querying for it is the best solution I know.As much as I know you can not use anonymous type return values in another method, because it won't just be recognized.However, they can be used in the same method.
I used to return them as IQueryable or IEnumerable, though it still does not let you see what is inside of the anonymous type variable.
I run into something like this before while I was trying to refactor some code, you can check it here : Refactoring and creating separate methods
You can only use dynamic keyword,
dynamic obj = GetAnonymousType();
Console.WriteLine(obj.Name);
Console.WriteLine(obj.LastName);
Console.WriteLine(obj.Age);
public static dynamic GetAnonymousType()
{
return new { Name = "John", LastName = "Smith", Age=42};
}
But with dynamic type keyword you will loose compile time safety, IDE IntelliSense etc...
With reflection.
public object tst() {
var a = new {
prop1 = "test1",
prop2 = "test2"
};
return a;
}
public string tst2(object anonymousObject, string propName) {
return anonymousObject.GetType().GetProperties()
.Where(w => w.Name == propName)
.Select(s => s.GetValue(anonymousObject))
.FirstOrDefault().ToString();
}
Sample:
object a = tst();
var val = tst2(a, "prop2");
Output:
test2
It is actually possible to return an anonymous type from a method in a particular use-case. Let's have a look!
With C# 7 it is possible to return anonymous types from a method, although it comes with a slight constraint. We are going to use a new language feature called local function together with an indirection trick (another layer of indirection can solve any programming challenge, right?).
Here's a use-case I recently identified. I want to log all configuration values after I have loaded them from AppSettings. Why? Because there's some logic around missing values that revert to default values, some parsing and so on. An easy way to log the values after applying the logic is to put them all in a class and serialize it to a logfile (using log4net). I also want to encapsulate the complex logic of dealing with settings and separate that from whatever I need to do with them. All without creating a named class that exists just for a single use!
Let's see how to solve this using a local function that creates an anonymous type.
public static HttpClient CreateHttpClient()
{
// I deal with configuration values in this slightly convoluted way.
// The benefit is encapsulation of logic and we do not need to
// create a class, as we can use an anonymous class.
// The result resembles an expression statement that
// returns a value (similar to expressions in F#)
var config = Invoke(() =>
{
// slightly complex logic with default value
// in case of missing configuration value
// (this is what I want to encapsulate)
int? acquireTokenTimeoutSeconds = null;
if (int.TryParse(ConfigurationManager.AppSettings["AcquireTokenTimeoutSeconds"], out int i))
{
acquireTokenTimeoutSeconds = i;
}
// more complex logic surrounding configuration values ...
// construct the aggregate configuration class as an anonymous type!
var c = new
{
AcquireTokenTimeoutSeconds =
acquireTokenTimeoutSeconds ?? DefaultAcquireTokenTimeoutSeconds,
// ... more properties
};
// log the whole object for monitoring purposes
// (this is also a reason I want encapsulation)
Log.InfoFormat("Config={0}", c);
return c;
});
// use this configuration in any way necessary...
// the rest of the method concerns only the factory,
// i.e. creating the HttpClient with whatever configuration
// in my case this:
return new HttpClient(...);
// local function that enables the above expression
T Invoke<T>(Func<T> func) => func.Invoke();
}
I have succeeded in constructing an anonymous class and also encapsulated the logic of dealing with complex settings management, all inside CreateHttpClient and within its own "expression". This might not be exactly what the OP wanted but it is a lightweight approach with anonymous types that is currently possible in modern C#.
Another option could be using automapper: You will be converting to any type from your anonymous returned object as long public properties matches.
The key points are, returning object, use linq and autommaper.
(or use similar idea returning serialized json, etc. or use reflection..)
using System.Linq;
using System.Reflection;
using AutoMapper;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
namespace UnitTestProject1
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var data = GetData();
var firts = data.First();
var info = firts.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public).First(p => p.Name == "Name");
var value = info.GetValue(firts);
Assert.AreEqual(value, "One");
}
[TestMethod]
public void TestMethod2()
{
var data = GetData();
var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
var mapper = config.CreateMapper();
var users = data.Select(mapper.Map<User>).ToArray();
var firts = users.First();
Assert.AreEqual(firts.Name, "One");
}
[TestMethod]
public void TestMethod3()
{
var data = GetJData();
var users = JsonConvert.DeserializeObject<User[]>(data);
var firts = users.First();
Assert.AreEqual(firts.Name, "One");
}
private object[] GetData()
{
return new[] { new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } };
}
private string GetJData()
{
return JsonConvert.SerializeObject(new []{ new { Id = 1, Name = "One" }, new { Id = 2, Name = "Two" } }, Formatting.None);
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
}
}
Now with local functions especially, but you could always do it by passing a delegate that makes the anonymous type.
So if your goal was to run different logic on the same sources, and be able to combine the results into a single list. Not sure what nuance this is missing to meet the stated goal, but as long as you return a T and pass a delegate to make T, you can return an anonymous type from a function.
// returning an anonymous type
// look mom no casting
void LookMyChildReturnsAnAnonICanConsume()
{
// if C# had first class functions you could do
// var anonyFunc = (name:string,id:int) => new {Name=name,Id=id};
var items = new[] { new { Item1 = "hello", Item2 = 3 } };
var itemsProjection =items.Select(x => SomeLogic(x.Item1, x.Item2, (y, i) => new { Word = y, Count = i} ));
// same projection = same type
var otherSourceProjection = SomeOtherSource((y,i) => new {Word=y,Count=i});
var q =
from anony1 in itemsProjection
join anony2 in otherSourceProjection
on anony1.Word equals anony2.Word
select new {anony1.Word,Source1Count=anony1.Count,Source2Count=anony2.Count};
var togetherForever = itemsProjection.Concat(otherSourceProjection).ToList();
}
T SomeLogic<T>(string item1, int item2, Func<string,int,T> f){
return f(item1,item2);
}
IEnumerable<T> SomeOtherSource<T>(Func<string,int,T> f){
var dbValues = new []{Tuple.Create("hello",1), Tuple.Create("bye",2)};
foreach(var x in dbValues)
yield return f(x.Item1,x.Item2);
}
I am not sure of the name of this construct, I thought this was called an anonymous type but I might be wrong. Anyway I was looking for this:
private (bool start, bool end) InInterval(int lower, int upper)
{
return (5 < lower && lower < 10, 5 < upper && upper < 10);
}
private string Test()
{
var response = InInterval(2, 6);
if (!response.start && !response.end)
return "The interval did not start nor end inside the target";
else if (!response.start)
return "The interval did not start inside the target";
else if (!response.end)
return "The interval did not end inside the target";
else
return "The interval is inside the target";
}
Another style to call this could be:
var (start, end) = InInterval(2, 6);

Dynamic Expression using LINQ. How To Find the Kitchens?

I try do implement a user dynamic filter, where used selects some properties, selects some operators and selects also the values.
As I didn't find yet an answer to this question, I tried to use LINQ expressions.
Mainly I need to identify all houses which main rooms are kitchens(any sens, I know).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
//using System.Linq.Dynamic;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Room aRoom = new Room() { Name = "a Room" };
Room bRoom = new Room() { Name = "b Room" };
Room cRoom = new Room() { Name = "c Room" };
House myHouse = new House
{
Rooms = new List<Room>(new Room[] { aRoom }),
MainRoom = aRoom
};
House yourHouse = new House()
{
Rooms = new List<Room>(new Room[] { bRoom, cRoom }),
MainRoom = bRoom
};
House donaldsHouse = new House()
{
Rooms = new List<Room>(new Room[] { aRoom, bRoom, cRoom }),
MainRoom = aRoom
};
var houses = new List<House>(new House[] { myHouse, yourHouse, donaldsHouse });
//var kitchens = houses.AsQueryable<House>().Where("MainRoom.Type = RoomType.Kitchen");
//Console.WriteLine("kitchens count = {0}", kitchens.Count());
var houseParam = Expression.Parameter(typeof(House), "house");
var houseMainRoomParam = Expression.Property(houseParam, "MainRoom");
var houseMainRoomTypeParam = Expression.Property(houseMainRoomParam, "Type");
var roomTypeParam = Expression.Parameter(typeof(RoomType), "roomType");
var comparison = Expression.Lambda(
Expression.Equal(houseMainRoomTypeParam,
Expression.Constant("Kitchen", typeof(RoomType)))
);
// ???????????????????????? DOES NOT WORK
var kitchens = houses.AsQueryable().Where(comparison);
Console.WriteLine("kitchens count = {0}", kitchens.Count());
Console.ReadKey();
}
}
public class House
{
public string Address { get; set; }
public double Area { get; set; }
public Room MainRoom { get; set; }
public List<Room> Rooms { get; set; }
}
public class Room
{
public double Area { get; set; }
public string Name { get; set; }
public RoomType Type { get; set; }
}
public enum RoomType
{
Kitchen,
Bedroom,
Library,
Office
}
}
var kitchens = from h in houses
where h.MainRoom.Type == RoomType.Kitchen
select h;
But you must set the RoomType property on the rooms before.
Ok, edit:
so you must redefine:
var comparison = Expression.Lambda<Func<House, bool>>(...
Then, when you use it:
var kitchens = houses.AsQueryable().Where(comparison.Compile());
Edit #2:
Ok, here you go:
var roomTypeParam = Expression.Parameter(typeof(RoomType), "roomType");
// ???????????????????????? DOES NOT WORK
var comparison = Expression.Lambda<Func<House, bool>>(
Expression.Equal(houseMainRoomTypeParam,
Expression.Constant(Enum.Parse(typeof(RoomType), "Kitchen"), typeof(RoomType))), houseParam);
// ???????????????????????? DOES NOT WORK
var kitchens = houses.AsQueryable().Where(comparison);
Edit #3: Of, for your needs, I am out of ideas for now. I give you one last one:
Declare an extension method on the String type:
internal static object Prepare(this string value, Type type)
{
if (type.IsEnum)
return Enum.Parse(type, value);
return value;
}
Then use it in that expression like:
Expression.Constant("Kitchen".Prepare(typeof(RoomType)), typeof(RoomType))
That's because apparently enums are treated differently. That extension will leave the string unaltered for other types. Drawback: you have to add another typeof() there.
// ???????????????????????? DOES NOT WORK
var kitchens = houses.AsQueryable().Where(comparison);
The Where method takes a Func<House, bool> or a Expression<Func<House, bool>> as the parameter, but the variable comparison is of type LambdaExpression, which doesn't match. You need to use another overload of the method:
var comparison = Expression.Lambda<Func<House, bool>>(
Expression.Equal(houseMainRoomTypeParam,
Expression.Constant("Kitchen", typeof(RoomType))));
//now the type of comparison is Expression<Func<House, bool>>
//the overload in Expression.cs
public static Expression<TDelegate> Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters);
I wouldn't build the where clause in that way - I think it's more complex than it needs to be for your needs. Instead, you can combine where clauses like this:
var houses = new List<House>(new House[] { myHouse, yourHouse, donaldsHouse });
// A basic predicate which always returns true:
Func<House, bool> housePredicate = h => 1 == 1;
// A room name which you got from user input:
string userEnteredName = "a Room";
// Add the room name predicate if appropriate:
if (!string.IsNullOrWhiteSpace(userEnteredName))
{
housePredicate += h => h.MainRoom.Name == userEnteredName;
}
// A room type which you got from user input:
RoomType? userSelectedRoomType = RoomType.Kitchen;
// Add the room type predicate if appropriate:
if (userSelectedRoomType.HasValue)
{
housePredicate += h => h.MainRoom.Type == userSelectedRoomType.Value;
}
// MainRoom.Name = \"a Room\" and Rooms.Count = 3 or
// ?????????????????????????
var aRoomsHouses = houses.AsQueryable<House>().Where(housePredicate);
I tested this one, honest :)
what about this
var kitchens = houses
.SelectMany(h => h.Rooms, (h, r) => new {House = h, Room = r})
.Where(hr => hr.Room.Type == RoomType.Kitchen)
.Select(hr => hr.House);
To add a new Enum type to dynamic Linq, you must add the following code :
typeof(Enum),
typeof(T)
T : Enum type
in predefined types of dynamic. That works for me.

Categories