I have the following class
public class School
{
public List<Student> Students { get; set; }
public List<Teacher> Teachers { get; set; }
}
Now i have this method
public bool Evaluate(??)
{
var school = DbContext.Schools.FirstOrDefault();
return school.??.Any(/*some expresions*/)
}
I should be able to pass a value in ?? and use it so that i can use both
return school.Students.Any(/*some expresions*/)
return school.Teachers.Any(/*some expresions*/)
So how can i replace the question marks with Students or Teachers ?
Edit:
public class Student
{
public string FullName { get; set; }
public bool Registered { get; set; }
public bool Passed { get; set; }
}
public class Teacher
{
public string FullName { get; set; }
public bool CanEvaluate { get; set; }
public bool Validator { get; set; }
}
public class DynamicCheckTest
{
public bool MyExpression<T>(List<T> items, string name,
Expression<Func<T, bool>> expression)
{
return items.Any(x => expression.Compile()(x));
}
}
public static bool Check<T>(this List<T> items, Func<T, bool> compiledExp)
{
return items.Any(x => compiledExp(x));
}
Students.Check(x => x.Name == "Mike" && x.Registered); // example
Teachers.Check(x => x.Name == "Jack" && x.CanEvaluate);// example
Now i have to pass the school along which contains both Students and Teachers
But i don't know which one will be called in advance
You could use this method:
public bool Evaluate<T>(Func<School, List<T>> project, Func<T, bool> filter)
{
var school = DbContext.Schools.FirstOrDefault();
return project(school).Any(filter);
}
If we assume that the implementation of Student and Teacher are this:
public class Student
{
public string Name;
}
public class Teacher
{
public string Subject;
}
Then you could do this:
bool hasFred = Evaluate(school => school.Students, student => student.Name == "Fred Nerk");
bool teachArt = Evaluate(school => school.Teachers, teacher => teacher.Subject == "Art");
Addressing the "Pass property name as parameter" request, you could use reflection for that, but I don't think that's a good way to go. Instead, a Func<School, List<TElement>> could be used to select the desired List<> property to evaluate...
public bool Evaluate<TElement>(Func<School, List<TElement>> listSelector)
where TElement : Person
{
School school = DbContext.Schools.FirstOrDefault();
DateTime today = DateTime.Today;
return listSelector(school)
// For example, check if today is the birthday of anyone in the selected list
.Any(person => person.DateOfBirth.Month == today.Month && person.DateOfBirth.Day == today.Day);
}
As #Enigmativity points out, the type constraint is necessary in order to pass much of a meaningful condition to Any(), which also assumes/requires that Student and Teacher have common ancestry, like this...
public abstract class Person
{
public DateTime DateOfBirth
{
get;
}
}
public class Student : Person
{
}
public class Teacher : Person
{
}
You'd then use a lambda expression to specify the desired List<>...
bool isAnyStudentsBirthday = Evaluate(school => school.Students);
bool isAnyTeachersBirthday = Evaluate(school => school.Teachers);
This will work as long as the members you want Any() to consider are available in the constrained type (i.e. Person). If you wanted to filter using members specific to the Student or Teacher class, your best bet would be to use an approach like #Enigmativity's answer, where the filter itself is a parameter and receives the same derived type as the selected List<> stores.
Note that if you ever want to use Evaluate() with some other collection property of School that is not specifically List<>, or just knowing that all Any() needs is an IEnumerable<>, you could change the return type (last type parameter) of the Func<> to something less-restrictive...
Func<School, IList<TElement>>
Func<School, ICollection<TElement>>
Func<School, IEnumerable<TElement>>
Related
I have a Person class which contains a property that lazy loads (custom made lazy loading) the person address data through accessing the Item property. I would want it to be mapped to a POCO class. How could it be done?
In addition, is it possible to be mapped only if it has data (checking the HasData property) and mapped as null if there isn’t data?.
These are the source classes:
public class SourcePerson
{
public string Name { get; set; }
public MyLazyLoadingObject<SourceAddress> Address;
}
public class SourceAddress
{
public string City { get; set; }
public string Country { get; set; }
}
This is the custom lazy loading class (simplified):
public class MyLazyLoadingObject<T>
{
private int? _id;
private T _object;
public T Item
{
get
{
if (!_object.IsReaded)
{
_object.Read();
}
return _object;
}
}
public bool HasData
{
get
{
return _id.HasValue;
}
}
// Other non-relevant properties and methods
}
These are the destination classes:
public class DestinationPerson
{
public string Name { get; set; }
public DestinationAddress Address;
}
public class DestinationAddress
{
public string City { get; set; }
public string Country { get; set; }
}
Couldn't find conventional way of setting up conversion from MyLazyLoadingObject<T> to T and then T to some TDestination without code repetition.
But custom IObjectMapper implementation with some manual expression building does the job.
Here is the class that builds the mapping expression:
public class MyLazyLoadingObjectMapper : IObjectMapper
{
public bool IsMatch(TypePair context)
{
return context.SourceType.IsGenericType && context.SourceType.GetGenericTypeDefinition() == typeof(MyLazyLoadingObject<>);
}
public Expression MapExpression(TypeMapRegistry typeMapRegistry, IConfigurationProvider configurationProvider, PropertyMap propertyMap, Expression sourceExpression, Expression destExpression, Expression contextExpression)
{
var item = Expression.Property(sourceExpression, "Item");
Expression result = item;
if (item.Type != destExpression.Type)
{
var typeMap = configurationProvider.ResolveTypeMap(item.Type, destExpression.Type);
result = Expression.Invoke(typeMap.MapExpression, item, destExpression, contextExpression);
}
// source != null && source.HasData ? result : default(TDestination)
return Expression.Condition(
Expression.AndAlso(
Expression.NotEqual(sourceExpression, Expression.Constant(null)),
Expression.Property(sourceExpression, "HasData")
),
result,
Expression.Default(destExpression.Type)
);
}
}
All you need is to register it to the MapperRegistry:
AutoMapper.Mappers.MapperRegistry.Mappers.Add(new MyLazyLoadingObjectMapper());
and of course create the regular type maps (which I guess you already did):
cfg.CreateMap<SourceAddress, DestinationAddress>();
cfg.CreateMap<SourcePerson, DestinationPerson>();
I've achieved it this way:
cfg.CreateMap<SourcePerson, DestinationPerson>().ForMember(t => t.Address, o => o.MapFrom(s => (s.Address.HasData)? s.Address.Item : null));
This question already has an answer here:
Select template
(1 answer)
Closed 9 years ago.
I would like to apply the same SELECT to an amount of queries, how do i do this? I'm looking to make some kind of template i'm guessing?
var query = (from b in db.routes select new
{ name = b.name,
age = b.age});
I would like to predefine name=b.name and age = b.age.
Thanks
You can create a method with an IEnumerable<SomeBaseClassOrInterfacee> argument.
then you can do your select against given argument within the method.
public class Generic
{
protected Generic(string name, int age)
{
Name = name;
Age = age;
}
public string Name { get; private set; }
public int Age { get; private set; }
}
public class Human : Generic
{
public Human(string name, string surname, int age) : base(name, age)
{
Surname = surname;
}
public string Surname { get; private set; }
}
public class Pet : Generic
{
public Pet(string name, int registrationCode, int age)
: base(name, age)
{
RegistrationCode = registrationCode;
}
public int RegistrationCode { get; private set; }
}
static void Main(string[] args)
{
IEnumerable<Pet> pets = new List<Pet>();
IEnumerable<Human> palls = new List<Human>();
var resPets = SelectAgeGreaterThen10<Pet>(from p in pets where p.Name.StartsWith("A") select p);
var resHumans = SelectAgeGreaterThen10<Human>(from p in palls where p.Name.StartsWith("B") select p);
}
private static IEnumerable<T> SelectAgeGreaterThen10<T>(IEnumerable<Generic> source) where T : Generic
{
return from s in source where s.Age > 10 select (T)s;
}
The tricky bit with your example is that you're using an anonymous type - which means you can't write a method (you can't declare the return type) and you can't assign a lambda expression to a local variable (you need to be able specify a type to convert the lambda expression to).
You also can't just use type inference to return something from a generic method - as you wouldn't be able to specify just the input type. However, you can use type inference with a generic class:
public static class Functions<T>
{
public static Func<T, TResult> Create<TResult>(Func<T, TResult> func)
{
return func;
}
}
Then you can write:
var projection = Functions<Route>.Create(r => new { r.name, r.age });
var query = db.routes
.Select(projection)
...;
But if you really want to use the same projection in multiple places, you should consider creating a named result type instead - at which point you can use any of the other options, including a conversion method.
How's this look:
class NameAndAge
{
public String Name;
public Int32 Age;
}
class Whatever
{
public IEnumerable<NameAndAge> GetNameAndAges(IEnumerable<dynamic> enumerable)
{
return from b in enumerable select new NameAndAge { Name = b.name,
Age = b.age};
}
}
You'll probably want to replace dynamic in the argument type with whatever the type of the elements in db.routes are.
I have a first list of entities like this :
public partial class Networking :EntityBase
{
public virtual int NetWorkingId
{
get;
set;
}
public virtual string NetWorkingParam
{
get;
set;
}
public virtual System.DateTime NetWorkingDate
{
get;
set;
}
}
And I have a second list of entities like this:
public partial class PrivateNetwork :EntityBase
{
public virtual int PrivateNetworkId
{
get;
set;
}
public virtual int ContaId
{
get { return _contaId; }
set
{
if (_contaId != value)
{
if (Contact != null && Contact.ContaId != value)
{
Contact = null;
}
_contaId = value;
}
}
}
public virtual Nullable<System.DateTime> DateCreation
{
get;
set;
}
}
I want to collect these two lists in one and sort all the elements by date.
Is that possible ?
You can do this, although it's not very pretty, and you end up with an IEnumerable<object> so you have to check each item's type before you can use it:
IEnumerable<object> sorted = myNetworkingList
.Concat<object>(myPrivateNetworkList)
.OrderBy(n => n is Networking
? (DateTime?)((Networking)n).NetWorkingDate
: ((PrivateNetwork)n).DateCreation);
foreach (object either in sorted)
{
if (either is Networking)
// Networking; do something
else
// PrivateNetwork; do something else
}
This problem could easily be solved by using polymorphism; use a common base class or interface for both classes, which has the DateTime property you want to sort on.
Example:
public abstract class NetworkingBase : EntityBase
{
public DateTime DateToSortOn { get; set; }
}
or
public interface INetworking
{
public DateTime DateToSortOn { get; set; }
}
And then make your classes derive from NetworkingBase or implement INetworking:
public partial class Networking : NetworkingBase
{
...
}
public partial class PrivateNetwork : NetworkingBase
{
...
}
or
public partial class Networking : EntityBase, INetworking
{
...
}
public partial class PrivateNetwork : EntityBase, INetworking
{
...
}
Do a LINQ Union or Concat and then an OrderBy on the resulting collection.
What I should have asked earlier is . . .
What do you want to do after you've sorted them?
The answer to this could have a big impact on the potential solution.
If the answer is something like I need to display a list of the dates, where you only need the dates in order. If so then you don't need to merge the two lists, you can get a sequence of just the ordered dates and use that e.g.
var orderedDates = networks.Select(n => n.NetworkingDate)
.Union(privateNetworks.Select(n => n.DateCreation))
.OrderBy(date => date);
If the answer is I need to display a list of links showing the Date that links to the Id of the object, and something to identify the type of object, then you could get away with something very like the above, with an Anonymous object.
var orderedDates = networks.Select(n => new {Date = n.NetworkingDate, Id = n.NetWorkingId, NetworkType = n.GetType().Name})
.Union(privateNetworks.Select(n => new {Date = n.DateCreation, Id = n.PrivateNetWorkingId, NetworkType = n.GetType().Name}))
.OrderBy(n => n.Date);
However if the answer is I need to send a Shutdown() command to the 10 oldest networks then you really do need a polymorphic solution, where you have a single type that you can call a Shutdown() method on, that will resolve to the specific Shutdown() method on the types you're using.
A Polymorphic solution to use only if user khellang's answer doesn't work for you
From a comment on another answer
#BinaryWorrier I chose this answer because I already have records in
the database, so if I choose to add a new interface how will I deal
with the records already stored before adding the interface ?
I find it difficult to believe that your ORM won't allow you to add an interface to an entity class and not - somehow - mark that interface and/or it's member so they're ignored by the ORM.
However, assuming you can't add a new interface or base class, you can still do this polymorphically.
Add the interface, add a class implementing the interface that for each of your Network classes (the Abstractor classes), then transform the network classes into Abstractor classes, adding them to a List<INetwork> and sorting that list.
public interface INetwork
{
DateTime? Date { get; }
}
public class PrivateNetworkAbstractor
:INetwork
{
private PrivateNetwork network;
public PrivateNetworkAbstractor(PrivateNetwork network)
{
this.network = network;
}
public DateTime? Date
{
get { return network.DateCreation; }
}
}
public class NetworkingAbstractor
: INetwork
{
private Networking networking;
public NetworkingAbstractor(Networking networking)
{
this.networking = networking;
}
public DateTime? Date
{
get { return networking.NetWorkingDate; }
}
}
...
public IEnumerable<INetwork> MergenSort(IEnumerable<Networking> generalNetWorks, IEnumerable<PrivateNetwork> privateNetWorks)
{
return generalNetWorks.Select(n => new NetworkingAbstractor(n)).Cast<INetwork>()
.Union(privateNetWorks.Select(n => new PrivateNetworkAbstractor(n)).Cast<INetwork>())
.OrderBy(n=> n.Date);
}
Create an interface that has the date and implement in in both classes. After that sorting is easy.
public interface INetwork
{
DateTime? Date { get; }
}
public partial class Networking :EntityBase, INetwork
{
public DateTime? Date
{
get { return NetWorkingDate; }
}
}
public partial class PrivateNetwork :EntityBase, INetwork
{
public DateTime? Date
{
get { return DateCreation; }
}
}
var commonList = new List<INetwork>();
// Add instances of PrivateNetwork and Networking to the list
var orderedByDate = commonList.OrderBy(n => n.Date);
First solution is using anonymous type
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Example1
{
class Program
{
class Human
{
public string Name { get; set; }
public string Hobby { get; set; }
public DateTime DateOfBirth { get; set; }
}
class Animal
{
public string Name { get; set; }
public string FavouriteFood { get; set; }
public DateTime DateOfBirth { get; set; }
}
static void Main(string[] args)
{
var humans = new List<Human>
{
new Human
{
Name = "Kate",
Hobby = "Fitness",
DateOfBirth = DateTime.Now.AddYears(-27),
},
new Human
{
Name = "John",
Hobby = "Cars",
DateOfBirth = DateTime.Now.AddYears(-32),
},
};
var animals = new List<Animal>
{
new Animal
{
Name = "Fluffy",
FavouriteFood = "Grain",
DateOfBirth = DateTime.Now.AddYears(-2),
},
new Animal
{
Name = "Bongo",
FavouriteFood = "Beef",
DateOfBirth = DateTime.Now.AddYears(-6),
},
};
var customCollection = (from human in humans
select new
{
Name = human.Name,
Date = human.DateOfBirth,
}
).Union(from animal in animals
select new
{
Name = animal.Name,
Date = animal.DateOfBirth,
}).OrderBy(x => x.Date);
foreach (dynamic customItem in customCollection)
Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name));
Console.Read();
}
}
}
or without anonymous type (created CustomClass):
...
class CustomClass
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
...
var customCollection = (from human in humans
select new CustomClass
{
Name = human.Name,
Date = human.DateOfBirth,
}
).Union(from animal in animals
select new CustomClass
{
Name = animal.Name,
Date = animal.DateOfBirth,
}).OrderBy(x => x.Date);
foreach (CustomClass customItem in customCollection)
Console.WriteLine(String.Format("Date: {0}, Name: {1}", customItem.Date, customItem.Name));
...
I simply added a base class and assigned it as the parent of both list's classes . and then simple did the union . it made the trick
Say I have a value object class, FullName, that is used as a property in an Employee entity class. The FullName may have a middle initial, nick name, etc; but from a domain perspective I would like to only enforce that both the FirstName and LastName properties of the FullName are valued.
I want to express this as part of an EmployeeValidator : ValidationDef{Employee} object, as opposed to an attribute.
Do I first need to make a class validator for FullName (ie, FirstAndLAstNameRequired) and then say that the FullName property in Employee is Valid (using some loquacious form of the ValidAttribute)?
As an aside, it seems that this documentation is still the best out there, but it does look dated at three years old. Is there anything newer that I missed?
Cheers,
Berryl
UPDATE
I haven't figured this out yet, but I have found what is likely the best source of NHib Validator info here: http://fabiomaulo.blogspot.com/search/label/Validator
Here is some psuedo code to express the question better too:
/// <summary>A person's name.</summary>
public class FullName
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string MiddleName { get; set; }
public virtual string NickName { get; set; }
}
public class EmployeeValidator : ValidationDef<Employee>
{
public EmployeeValidator()
{
Define(x => x.FullName).FirstAndLastNameRequired(); // how to get here!!
}
}
UPDATE FOR DAVID
public class FullNameValidator : ValidationDef<FullName>
{
public FullNameValidator() {
Define(n => n.FirstName).NotNullable().And.NotEmpty().And.MaxLength(25);
Define(n => n.LastName).NotNullable().And.NotEmpty().And.MaxLength(35);
// not really necessary but cool that you can do this
ValidateInstance
.By(
(name, context) => !name.FirstName.IsNullOrEmptyAfterTrim() && !name.LastName.IsNullOrEmptyAfterTrim())
.WithMessage("Both a First and Last Name are required");
}
}
public class EmployeeValidator : ValidationDef<Employee>
{
public EmployeeValidator()
{
Define(x => x.FullName).IsValid(); // *** doesn't compile !!!
}
}
To get the FullName validated when you validate the employee, I think you'd do something like the following:
public class EmployeeValidator : ValidationDef<Employee>
{
public EmployeeValidator()
{
Define(x => x.FullName).IsValid();
Define(x => x.FullName).NotNullable(); // Not sure if you need this
}
}
Then the FullName Validator would just be something like:
public class FullNameValidator : ValidationDef<FullName>
{
public EmployeeValidator()
{
Define(x => x.FirstName).NotNullable();
Define(x => x.LastName).NotNullable();
}
}
Alternatively I think you could do something like (haven't checked the syntax):
public class EmployeeValidator: ValidationDef<Employee>
{
public EmployeeValidator() {
ValidateInstance.By((employee, context) => {
bool isValid = true;
if (string.IsNullOrEmpty(employee.FullName.FirstName)) {
isValid = false;
context.AddInvalid<Employee, string>(
"Please enter a first name.", c => c.FullName.FirstName);
} // Similar for last name
return isValid;
});
}
}
Give a class like below, how can i find the name of one particluar property?
public class Student
{
public int Grade
{
get;
set;
}
public string TheNameOfTheGradeProperty
{
get
{
return ????
}
}
// More properties..
}
So i would like to return the string "Grade" from the TheNameOfTheGradeProperty property. The reason i'm asking is that i do not want to use a hardcoded string, but rather a lambda expression or something else.
How can i acheive this?
It is possible to use an expression to find the name of the property, using a simple extension method you can use it on any object... if you need to restrict it to a set of objects you can apply a generic constraint on T. Hope this helps
public class Student
{
public int Grade { get; set;}
public string Name { get; set; }
public string GradePropertyName
{
get { return this.PropertyName(s => s.Grade); }
}
public string NamePropertyName
{
get { return this.PropertyName(s => s.Name); }
}
}
public static class Helper
{
public static string PropertyName<T, TProperty>(this T instance, Expression<Func<T, TProperty>> expression)
{
var property = expression.Body as MemberExpression;
if (property != null)
{
var info = property.Member as PropertyInfo;
if (info != null)
{
return info.Name;
}
}
throw new ArgumentException("Expression is not a property");
}
}
You have a very strange request. Are you saying you want to not use a hard-coded string because you want TheNameOfTheGradeProperty to stay up to date if you refactor the class? If so, here's a strange way to do so:
public class Student
{
public int Grade { get; set; }
public string TheNameOfTheGradeProperty
{
get
{
Expression<Func<int>> gradeExpr = () => this.Grade;
MemberExpression body = gradeExpr.Body as MemberExpression;
return body.Member.Name;
}
}
}
using System.Reflection;
return typeof(Student).GetProperty("Grade").Name;
But as you can see, you're not that far ahead using reflection (in this manner) because the "Grade" string is still hard-coded which means in this scenario it's more efficient just to return "Grade".
One thing I like to do is create and add a custom attribute to a member like so. The following prevents you from having to use the hard-coded string "Grade".
public class Student {
// TAG MEMBER WITH CUSTOM ATTRIBUTE
[GradeAttribute()]
public int Grade
{
get;
set;
}
public string TheNameOfTheGradeProperty
{
get
{
/* Use Reflection.
Loop over properties of this class and return the
name of the one that is tagged with the
custom attribute of type GradeAttribute.
*/
}
}
// More properties..
}
Creating custom attributes can be found here.