I'm doing a unit test in my design class, and the shell of the project was given to us. There is only one method in the unit test where I have to add code. I can't change anything else in the code.
I have tried everything I could think of using what C++ knowledge I have and tried Googling different ways to solve this problem. Every result that came up was either too complex because I don't have a background with C#, or the information for what I was looking for was not given.
Here is the original code:
class Course
{
public Course(string id, string title, int creditHours, string description, string prerequisiteCourse)
{
this.CourseID = id;
this.CourseTitle = title;
this.CreditHours = creditHours;
this.Description = description;
this.PrerequisiteCourse = prerequisiteCourse;
}
public string CourseID;
public string CourseTitle;
public int CreditHours;
public string Description;
public string PrerequisiteCourse;
}
class CourseListTest
{
public static void Main(string[] args)
{
GetCourseByCourseIDTestWhenCourseExists();
GetCourseByCourseIDTestWhenCourseDoesNotExist();
}
public static void GetCourseByCourseIDTestWhenCourseExists()
{
CourseList myCourseList = new CourseList();
Course myCourse = myCourseList.GetCourseByCourseID("CIS 400");
if (myCourse.CourseID != "CIS 400")
System.Console.WriteLine("ERROR - GetCourseByCourseIDTestWhenCourseExists(): Returned CourseID Not equal (CIS 400)");
}
public static void GetCourseByCourseIDTestWhenCourseDoesNotExist()
{
CourseList myCourseList = new CourseList();
Course myCourse = myCourseList.GetCourseByCourseID("CIS 101");
if (myCourse != null)
System.Console.WriteLine("ERROR - GetCourseByCourseIDTestWhenCourseDoesNotExist(): should have returned null");
}
}
Here is were the problem lies in the next class. We are to enter code into the GetCourseByCourseID method which is where I get stuck.
class CourseList
{
public Course[] CourseArray =
{
new Course ("CIS 400", "OO Analysis & Design", 4, "Important class", "CIS 110") ,
new Course ("CIS 150A" , "VB.NET Programming", 4, "Good Introduction to programming", "CIS 100") ,
new Course ("CIS 150B", "C# Programming with labs", 4, "Follow-up to CIS 100", "CIS 100")
};
public Course GetCourseByCourseID(string id)
{
}
}
Since "CIS 101" is not a course in the CourseList we have to return null. The whole point of the exercise is to get the console to display nothing. That means the code is working properly.
I don't want the answer. I was just wanted an example of how to get this to work. Being that the code was already given to us.
i'll keep this close to c++ syntax.
there are many other ways but...
public Course GetCourseByCourseID(string id)
{
for(int x = 0; x < CourseArray.Length; x++)
{
if(CourseArray[x].CourseID == id) {return CourseArray[x];}
}
return null;
}
your array is static you could just use x < 3
and for a more c# way
using System.Linq;
public Course GetCourseByCourseID(string id)
{
return CourseArray.Where(a => a.CourseID == id).FirstOrDefault();
}
a is each course and First return the first element in the resulting collection. a pit fall with this approach is that if you have more than one Course with the same id you only get the first one.
but then that is likely a design flaw.
it should be noted that if CourseArray were to be multidimensional. then length would not be usable because it return the total number of elements in all dimensions of the array. thus using System.Linq Count() extension method would have to be used.
The simplest way would be to use a foreach loop, checking through all the courses until the ID matches. If no ID matches, the loop will exit and you should return null.
The more 'advanced' way would be to use LINQ, either straight up LINQ or the extension methods to achieve the same result but with less code.
With any language it is best to state a return variable which will start in a failure state. Then do the work of trying to find the non failure state and assign it to the return variable. If one doesn't find a non failure state, no assignment is done and the return value is correct as null.
Example:
public Course GetCourseByCourseID(string id)
{
Course foundCourse = null;
if (CourseArray != null)
{
// Check course array here for the id and if one is found, assign to foundCourse.
}
return foundCourse;
}
So within the if's you can continue to remove any possible failure situations. The one above in the if checks CourseArray for null. If it is null it gracefully exits and doesn't throw an exception about trying to check CourseArray. Keep doing 'sanity' checks where possible and it makes for better programming.
Related
I am using linq2db and while it works well enough for most CRUD operations I have encountered many expressions that it just cannot translate into SQL.
It has gotten to the point where unless I know in advance exactly what kinds of expressions will be involved and have successfully invoked them before, I am worried that any benefit derived from linq2db will be outweighed by the cost of trying to find and then remove (or move away from the server side) the offending expressions.
If I knew how to tell linq2db how to parse an Expression<Func<T,out T>> or whatnot into SQL whenever on an ad-hoc, as-it-is-needed basis, then I would be much more confident and I could do many things using this tool.
Take, for instance, String.Split(char separator), the method that takes a string and a char to return a string[] of each substring between the separator.
Suppose my table Equipment has a nullable varchar field Usages that contains lists of different equipment usages separated by commas.
I need to implement IList<string> GetUsages(string tenantCode, string needle = null) that will give provide a list of usages for a given tenant code and optional search string.
My query would then be something like:
var listOfListOfStringUsages =
from et in MyConnection.GetTable<EquipmentTenant>()
join e in MyConnection.GetTable<Equipment>() on et.EquipmentId = e.EquipmentId
where (et.TenantCode == tenantCode)
where (e.Usages != null)
select e.Usages.Split(','); // cannot convert to sql here
var flattenedListOfStringUsages =
listOfListOfStringUsages.SelectMany(strsToAdd => strsToAdd)
.Select(str => str.Trim())
.Distinct();
var list = flattenedListOfStringUsages.ToList();
However, it would actually bomb out at runtime on the line indicated by comment.
I totally get that linq2db's creators cannot possibly be expected to ship with every combination of string method and major database package.
At the same time I feel as though could totally tell it how to handle this if I could just see an example of doing just that (someone implementing a custom expression).
So my question is: how do I instruct linq2db on how to parse an Expression that it cannot parse out of the box?
A few years ago I wrote something like this:
public class StoredFunctionAccessorAttribute : LinqToDB.Sql.FunctionAttribute
{
public StoredFunctionAccessorAttribute()
{
base.ServerSideOnly = true;
}
// don't call these properties, they are made private because user of the attribute must not change them
// call base.* if you ever need to access them
private new bool ServerSideOnly { get; set; }
private new int[] ArgIndices { get; set; }
private new string Name { get; set; }
private new bool PreferServerSide { get; set; }
public override ISqlExpression GetExpression(System.Reflection.MemberInfo member, params ISqlExpression[] args)
{
if (args == null)
throw new ArgumentNullException("args");
if (args.Length == 0)
{
throw new ArgumentException(
"The args array must have at least one member (that is a stored function name).");
}
if (!(args[0] is SqlValue))
throw new ArgumentException("First element of the 'args' argument must be of SqlValue type.");
return new SqlFunction(
member.GetMemberType(),
((SqlValue)args[0]).Value.ToString(),
args.Skip(1).ToArray());
}
}
public static class Sql
{
private const string _serverSideOnlyErrorMsg = "The 'StoredFunction' is server side only function.";
[StoredFunctionAccessor]
public static TResult StoredFunction<TResult>(string functionName)
{
throw new InvalidOperationException(_serverSideOnlyErrorMsg);
}
[StoredFunctionAccessor]
public static TResult StoredFunction<TParameter, TResult>(string functionName, TParameter parameter)
{
throw new InvalidOperationException(_serverSideOnlyErrorMsg);
}
}
...
[Test]
public void Test()
{
using (var db = new TestDb())
{
var q = db.Customers.Select(c => Sql.StoredFunction<string, int>("Len", c.Name));
var l = q.ToList();
}
}
(and of course you can write your wrappers around Sql.StoredFunction() methods to get rid of specifying function name as a string every time)
Generated sql (for the test in the code above):
SELECT
Len([t1].[Name]) as [c1]
FROM
[dbo].[Customer] [t1]
PS. We use linq2db extensively in our projects and completely satisfied with it. But yes, there is a learning curve (as with almost everything serious we learn) and one needs to spend some time learning and playing with the library in order to feel comfortable with it and see all the benefits it can give.
Try listOfListOfStringUsages.AsEnumerable(). It will enforce executing SelectMany on client side.
UPDATE:
I used the following code to reproduce the issue:
var q =
from t in db.Table
where t.StringField != null
select t.StringField.Split(' ');
var q1 = q
//.AsEnumerable()
.SelectMany(s => s)
.Select(s => s.Trim())
.Distinct()
.ToList();
It's not working. But if I uncomment .AsEnumerable(), it works just fine.
I keep getting stuck on this issue and have done a lot of searching/reading to try to understand the problem, but I just don't get it. Am wondering if someone can provide me with an example of how to update object values while looping an IEnumerable<>.
Example:
public class MyClass
{
private IEnumerable<MyData> _MyData = null;
public MyClass() {}
public MyClass(string parm1, int parm2) { Load(parm1, parm2); }
public IEnumerable<MyData> Load(string parm1, int parm2)
{
_MyData = _dbContext.MyData.Where(m => m.Parm1 == parm1 && m.Parm2 == parm2);
foreach(MyData mydata in _MyData)
{
if(mydata.Parm2 == 1)
{
mydata.Parm1 = "Some value";
}
}
return _MyData;
}
}
The above code doesn't work as any changes made to mydata.Parm1 within the loop are not retained. I read an SO article that suggested to make changes like this:
for (int i = 0; i < _MyData.Count(); i++)
{
_MyData.Skip(i).FirstOrDefault().Parm1 = "Some Value";
}
This works, but it's really ugly and hard for me to believe there isn't a cleaner way. For a single change it might be acceptable, but I have several changes that need to be made. So I've attempted this:
for (int i = 0; i < _MyData.Count(); i++)
{
MyData md = _MyData.ElementAt(i);
md.Parm1 = "Some Value";
}
But I don't understand how to put the modified md back into _MyData to save changes.
I think the main reason I'm going through all of these hoops is that I don't understand how to make changes to the elements and have them retained. Any changes I make seem to revert back to their original values unless I go through these hoops. Maybe someone can point out where I'm going wrong. I would like to use this class like this:
IEnumerable<MyData> MyDataResult = new MyClass("Parm1", 4);
Using the above line of code, I can trace through the Load() function and see that the desired changes are being made, but once finished MyDataResult contains the original values instead of those I saw being changed.
It is more then obvious that my code is wrong, but I hope I've been clear enough to illustrate what I'm wanting to do and where I'm having difficulty.
Try this -
_MyData = _dbContext.MyData.Where(m => m.Parm1 == parm1 && m.Parm2 == parm2).ToList();
To be clear, essentially what you have in your current code is a query, which you are enumerating in your Load method, trying to update some of its properties, but then in the end, you end up returning the query, and not the updated values in the query.
The caller of Load method, will end up running the query a second time, only to see direct values from the database.
Adding .ToList to the end of the query in Load method, materializes the query, and then you are doing rest of the operations in memory.
EDIT:
Just in case, if there would be performance concern over the large amount of data this query may return, then you could also consider this alternate approach -
public IEnumerable<MyData> Load(string parm1, int parm2)
{
_MyData = _dbContext.MyData.Where(m => m.Parm1 == parm1 && m.Parm2 == parm2);
foreach(MyData mydata in _MyData)
{
if(mydata.Parm2 == 1)
{
mydata.Parm1 = "Some value";
}
yield return myData;
}
}
This would keep the query lazy, and still return the modified values, as caller of Load iterates over the IEnumerable<MyData> returned by Load.
Not sure why you are returning a value which never gets used. You just need to set _MyData in your Load method as it is a class level variable.
Change Load to not return a value and ToList() your query on the db context and then set your _MyData to your concrete list object in Load.
Something like this will work - I've simplified your example slightly but same principals:
public class MyClass
{
public IEnumerable<string> _MyData = null;
public IEnumerable<string> _dbContext = new List<string> {"a", "b", "aa", "bb"};
public MyClass(){}
public MyClass(string parm1, int parm2){Load(parm1, parm2);}
public void Load(string parm1, int parm2)
{
var somedata = _dbContext.Where(m => m.Length == 2).ToList();
var myData = somedata.Select(s => s == parm1 ? "something else" : s).ToList();
_MyData = myData;
}
}
Use can use
var a = new MyClass("aa",1)._MyData;
and "aa" will get replaced with "something else" and be returned to "a".
You can't use a class like this:
IEnumerable<MyData> MyDataResult = new MyClass("Parm1", 4);
If you ask for an MyClass you'll get a MyClass not an IEnumerable.
If your call to dbContext is to an underlying data source you may be better off not doing that in the class constructor and always call Load explicitly following class construction. You then have options to avoid thread blocking on a potentially long running I/O operation.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
So, it's pretty well known that the infamous NullReferenceException is the most common exception in software products. I've been reading some articles, and found myself with the Optional approach.
Its aim is to create some kind of encapsulation around a nullable value
public sealed class Optional<T> where T : class {
private T value;
private Optional(T value) {
this.value = value;
}
//Used to create an empty container
public static Optional<T> Empty() {
return new Optional(null);
}
//Used to create a container with a non-null value
public static Optional<T> For(T value) {
return new Optional(value);
}
//Used to check if the container holds a non-null value
public bool IsPresent {
get { return value != null; }
}
//Retrieves the non-null value
public T Value {
get { return value; }
}
}
Afterwards, the now optional value can be returned like this:
public Optional<ICustomer> FindCustomerByName(string name)
{
ICustomer customer = null;
// Code to find the customer in database
if(customer != null) {
return Optional.Of(customer);
} else {
return Optional.Empty();
}
}
And handled like this:
Optional<ICustomer> optionalCustomer = repository.FindCustomerByName("Matt");
if(optionalCustomer.IsPresent) {
ICustomer foundCustomer = optionalCustomer.Value;
Console.WriteLine("Customer found: " + customer.ToString());
} else {
Console.WriteLine("Customer not found");
}
I don't see any improvement, just shifted complexity.
The programmer must remember to check if a value IsPresent, in the same way he must remember to check if a value != null.
And if he forgets, he would get a NullReferenceException on both approaches.
What am I missing? What advantages (if any) does the Optional pattern provide over something like Nullable<T> and the null coalescing operator?
Free your mind
If you think of Option as Nullable by a different name then you are absolutely correct - Option is simply Nullable for reference types.
The Option pattern makes more sense if you view it as a monad or as a specialized collection that contain either one or zero values.
Option as a collection
Consider a simple foreach loop with a list that cannot be null:
public void DoWork<T>(List<T> someList) {
foreach (var el in someList) {
Console.WriteLine(el);
}
}
If you pass an empty list to DoWork, nothing happens:
DoWork(new List<int>());
If you pass a list with one or more elements in it, work happens:
DoWork(new List<int>(1));
// 1
Let's alias the empty list to None and the list with one entry in it to Some:
var None = new List<int>();
var Some = new List(1);
We can pass these variables to DoWork and we get the same behavior as before:
DoWork(None);
DoWork(Some);
// 1
Of course, we can also use LINQ extension methods:
Some.Where(x => x > 0).Select(x => x * 2);
// List(2)
// Some -> Transform Function(s) -> another Some
None.Where(x => x > 0).Select(x => x * 2);
// List()
// None -> None
Some.Where(x => x > 100).Select(x => x * 2);
// List() aka None
// Some -> A Transform that eliminates the element -> None
Interesting side note: LINQ is monadic.
Wait, what just happened?
By wrapping the value that we want inside a list we were suddenly able to only apply an operation to the value if we actually had a value in the first place!
Extending Optional
With that consideration in mind, let's add a few methods to Optional to let us work with it as if it were a collection (alternately, we could make it a specialized version of IEnumerable that only allows one entry):
// map makes it easy to work with pure functions
public Optional<TOut> Map<TIn, TOut>(Func<TIn, TOut> f) where TIn : T {
return IsPresent ? Optional.For(f(value)) : Empty();
}
// foreach is for side-effects
public Optional<T> Foreach(Action<T> f) {
if (IsPresent) f(value);
return this;
}
// getOrElse for defaults
public T GetOrElse(Func<T> f) {
return IsPresent ? value : f();
}
public T GetOrElse(T defaultValue) { return IsPresent ? value: defaultValue; }
// orElse for taking actions when dealing with `None`
public void OrElse(Action<T> f) { if (!IsPresent) f(); }
Then your code becomes:
Optional<ICustomer> optionalCustomer = repository.FindCustomerByName("Matt");
optionalCustomer
.Foreach(customer =>
Console.WriteLine("Customer found: " + customer.ToString()))
.OrElse(() => Console.WriteLine("Customer not found"));
Not much savings there, right? And two more anonymous functions - so why would we do this? Because, just like LINQ, it enables us to set up a chain of behavior that only executes as long as we have the input that we need. For example:
optionalCustomer
.Map(predictCustomerBehavior)
.Map(chooseIncentiveBasedOnPredictedBehavior)
.Foreach(scheduleIncentiveMessage);
Each of these actions (predictCustomerBehavior, chooseIncentiveBasedOnPredictedBehavior, scheduleIncentiveMessage) is expensive - but they will only happen if we have a customer to begin with!
It gets better though - after some study we realize that we cannot always predict customer behavior. So we change the signature of predictCustomerBehavior to return an Optional<CustomerBehaviorPrediction> and change our second Map call in the chain to FlatMap:
optionalCustomer
.FlatMap(predictCustomerBehavior)
.Map(chooseIncentiveBasedOnPredictedBehavior)
.Foreach(scheduleIncentiveMessage);
which is defined as:
public Optional<TOut> FlatMap<TIn, TOut>(Func<TIn, Optional<TOut>> f) where TIn : T {
var Optional<Optional<TOut>> result = Map(f)
return result.IsPresent ? result.value : Empty();
}
This starts to look a lot like LINQ (FlatMap -> Flatten, for example).
Further possible refinements
In order to get more utility out of Optional we should really make it implement IEnumerable. Additionally, we can take advantage of polymorphism and create two sub-types of Optional, Some and None to represent the full list and the empty list case. Then our methods can drop the IsPresent checks, making them easier to read.
TL;DR
The advantages of LINQ for expensive operations are obvious:
someList
.Where(cheapOp1)
.SkipWhile(cheapOp2)
.GroupBy(expensiveOp)
.Select(expensiveProjection);
Optional, when viewed as a collection of one or zero values provides a similar benefit (and there's no reason it couldn't implement IEnumerable so that LINQ methods would work on it as well):
someOptional
.FlatMap(expensiveOp1)
.Filter(expensiveOp2)
.GetOrElse(generateDefaultValue);
Further suggested reading
Option (F#)
When null is not enough (C#)
The neophytes guide to Scala Part 5: The Option type
The Marvel of Monads (C#)
Eric Lippert's series on LINQ and monads
it would probally make more sense if you used something like this
interface ICustomer {
String name { get; }
}
public class OptionalCustomer : ICustomer {
public OptionalCustomer (ICustomer value) {
this.value = value;
}
public static OptionalCustomer Empty() {
return new OptionalCustomer(null);
}
ICustomer value;
public String name { get {
if (value == null ) {
return "No customer found";
}
return value.Name;
}
}
}
now if your pass an "empty" optional customer object you can still call the .Name property (without getting nullpointers)
The advantage of Optional is you know if something may not exist.
The problem with many types of queries that return a null is that that could mean 2 things:
The query didn't return a result
The query returned a result whose value was null.
I know you're asking specifically about C# but Java just introduced Optionals in Java 8 so there are a lot of articles about it so I'll use Java as an example. but it's completely the same idea as in C#:
Consider the Java Map.get(key) method
Object value = map.get(key);
if(value ==null){
//is there an entry in the map key =>null or does key not exist?
}
to get around that you have to have an additional method containsKey( k)
With optional, you only need one method
Optional<Object> result = map.get(key);
if(result.isPresent()){
Object value = result.get();
//if value is null, then we know that key =>null
}
More info see this Java article : http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html
Did you mean: Null Object pattern
The article linked to me in the comments contains a conclusion section explained this programming tool.
... The purpose of Optional is not to replace every single null reference in your codebase but rather to help design better APIs in which—just by reading the signature of a method—users can tell whether to expect an optional value. .... deal with the absence of a value; as a result, you protect your code against unintended null pointer exceptions.
Anyway, let it crash and find the reason. If you do not want endlessly embedded if statements than use an implementation pattern Guard Clause pattern, which says the following:
While programs have a main flow, some situations require deviations from the
main flow. The guard clause is a way to express simple and local exceptional
situations with purely local consequences.
Once I have the results of my Linq query, I am not always happy. There could be a result that I was expecting to be there but wasn't. For example, my client was expecting that a customer was in a customer list, but it wasn't. It is my client saying "Dude, where's my customer?", not me. I am the Dude, and to remain a dude, I have to give my client the reason.
Is there a simple way to take a given object instance and a Linq query and determine which expressions within the query excluded that instance?
Edit Ok, here is a better example
Output should be something along the lines:
Your Customer was excluded for 2 reasons:
Customer FirstName is Carl but it should be Daniel
Customer Age is 18 but it should be > 20
public class Customer
{
public string FirstName { get; set; }
public int Age { get; set; }
}
[Test]
public void Dude_wheres_my_object_test1()
{
var daniel = new Customer { FirstName = "Daniel", Age = 41 };
var carl = new Customer { FirstName = "Carl", Age= 18 };
var Customers = new List<Customer>() { daniel, carl };
// AsQueryable() to convert IEnumerable<T> to IQueryable<T> in
//the case of LinqtoObjects - only needed for this test, not
//production code where queies written for LinqToSql etc normally
//return IQueryable<T>
var query = from c in Customers.AsQueryable()
where c.Age > 20
where c.FirstName == "Daniel"
select c;
//query would return Daniel as you'd expect, but not executed here.
//However I want to explain why Carl was not in the results
string[] r = DudeWheresMyObject(query, carl);
Assert.AreEqual("Age is 18 but it should be > 20", r[0]);
Assert.AreEqual("FirstName is Carl but it should be Daniel", r[1]);
//Should even work for a Customer who is not
//in the original Customers collection...
var ficticiousCustomer = new Customer { FirstName = "Other", Age = 19};
string[] r2= DudeWheresMyObject(query,
ficticiousCustomer);
Assert.AreEqual("Age is 19 but it should be > 20", r2[0]);
Assert.AreEqual("FirstName is Other but it should be Daniel", r2[1]);
}
public string[] DudeWheresMyObject<T>(IQueryable<T> query, T instance)
{
//Do something here with the query.Expression and the instance
}
First of all, before I attempt to write some fancy Fluent framework, Has anyone done this already?
So far, I have considered navigating the expression tree and executing each branch against an IQueryable that only contains my object. Now I don't have a great deal of experience using raw expression trees, so I would like those who have to suggest any pitfalls or even explain whether this is a dead end and why.
I am anxious that anything that results from this should:
Be Reusable - Should be applicable to any object compared against a Linq query returning objects of the same class.
Not affect the performance of the original query (this should just be standard Linq).
Should be Linq-implementation agnostic.
If there are multiple property values set on the missing instance that excluded it from the results, then all of those reasons should be reported.
Edit
I am not suggesting that I keep executing LinqToSql against the database multiple times with different permutations of the query and comparing the results. Rather, I am looking for a way to take a single instance and compare it to the expression tree (without executing the query directly again)
Also, I would like an indication of whether others might find this useful. If so, I would consider starting an open source project to solve it.
I think you'd have to re-create the query as linq-to-objects and deal with the subtle differences between linq-to-sql/entities/whatever and linq-to-objects, accepting that some providers just won't work realistically.
You have your object you want to find in an in memory IEnumerable<T> or something.
You'd have to walk the expression tree somehow and snip out the leaves, so say you had:
where obj.foo == true && obj.bar == "yes"
you'd have to figure out that obj.foo == true and obj.bar == "yes" are leaves and start there. It'd be a sort of depth first search of the expression tree.
So, construct linq to objects queries that only had those leaves. See if the object is included in the results. If not then we've found out why it's excluded, if not then go up the tree (i.e. make the where query include more clauses, getting closer to the orignal one until the object disappears from the results).
As I see it the tough parts would be handling the differences between original linq to 'whatever' and link to objects, figuring out where to split the where claues, dealing with things like joins which can also exclude things and dealing with things like SqlMethods.Like that don't work in linq to objects.
For a one-off exploration of what's filtering out the result, it's hard to beat the Dump method in LINQPad. Here's an extract from one of their samples that shows it in action:
// Dump returns exactly what it was given, so you can sneakily inject
// a Dump (or even many Dumps) *within* an expression. This is useful
// for monitoring a query as it progresses:
new[] { 11, 5, 17, 7, 13 } .Dump ("Prime numbers")
.Where (n => n > 10) .Dump ("Prime numbers > 10")
.OrderBy (n => n) .Dump ("Prime numbers > 10 sorted")
.Select (n => n * 10) .Dump ("Prime numbers > 10 sorted, times 10!");
This gives nicely formatted tables of results:
With some fun expression hacking, you can see the results of each stage of the evaluation for each item in the set. Inspect the local result after the breakpoint has been hit to see the results of the evaluation. To actually use the results of the evaluation, just append .Where(x => x.IsIncludedInResult).Select(x => x.EvaluationTarget) to the line where the report is generated.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
namespace ConsoleApplication4
{
[DebuggerDisplay("{Condition} on {EvaluationTarget} is {EvaluationResult}")]
public class ReportItem<T>
{
public string Condition { get; private set; }
public IEnumerable<ReportItem<T>> NestedReports { get; private set; }
public object EvaluationResult { get; private set; }
public T EvaluationTarget { get; private set; }
public ReportItem(Expression condition, IEnumerable<ReportItem<T>> nestedReports, T evaluationTarget, object evaluationResult)
{
Condition = condition.ToString();
NestedReports = nestedReports;
EvaluationTarget = evaluationTarget;
EvaluationResult = evaluationResult;
}
public override string ToString()
{
return string.Format("{0} on {1} is {2}", Condition, EvaluationTarget, EvaluationResult);
}
}
[DebuggerDisplay("Included: {IsIncludedInResult} \n{Summary}")]
public class Report<T>
{
public ReportItem<T> Contents { get; private set; }
public T EvaluationTarget { get; private set; }
public Report(T source, Expression<Func<T, bool>> predicate)
{
EvaluationTarget = source;
IsIncludedInResult = predicate.Compile()(source);
Contents = Recurse(predicate.Parameters.Single(), predicate.Body, source);
}
private object Evaluate(Expression expression, ParameterExpression parameter, T source)
{
var expr = Expression.Lambda(expression, parameter);
var #delegate = expr.Compile();
var value = #delegate.DynamicInvoke(source);
return value;
}
private ReportItem<T> Recurse(ParameterExpression parameter, Expression sourceExpression, T source)
{
var constantExpression = sourceExpression as ConstantExpression;
if(constantExpression != null)
{
return new ReportItem<T>(sourceExpression, null, source, Evaluate(constantExpression, parameter, source));
}
var unaryExpression = sourceExpression as UnaryExpression;
if(unaryExpression != null)
{
var content = Recurse(parameter, unaryExpression.Operand, source);
var result = Evaluate(sourceExpression, parameter, source);
return new ReportItem<T>(sourceExpression, new[]{content}, source, result);
}
var binaryExpression = sourceExpression as BinaryExpression;
if(binaryExpression != null)
{
var left = Recurse(parameter, binaryExpression.Left, source);
var right = Recurse(parameter, binaryExpression.Right, source);
var item = new ReportItem<T>(sourceExpression, new[] {left, right}, source, Evaluate(sourceExpression, parameter, source));
return item;
}
var methodCallExpression = sourceExpression as MethodCallExpression;
if(methodCallExpression != null)
{
var args = methodCallExpression.Arguments.Select(x => Evaluate(x, parameter, source)).ToArray();
var result = methodCallExpression.Method.Invoke(Expression.Lambda(methodCallExpression.Object, parameter).Compile().DynamicInvoke(source), args);
return new ReportItem<T>(sourceExpression, null, source, result);
}
throw new Exception("Unhandled expression type " + sourceExpression.NodeType + " encountered");
}
public bool IsIncludedInResult { get; private set; }
public string Summary
{
get { return Contents.ToString(); }
}
public override string ToString()
{
return Summary;
}
}
public static class PredicateRunner
{
public static IEnumerable<Report<T>> Report<T>(this IEnumerable<T> set, Expression<Func<T, bool>> predicate)
{
return set.Select(x => new Report<T>(x, predicate));
}
}
class MyItem
{
public string Name { get; set; }
public int Value { get; set; }
public override int GetHashCode()
{
return Value % 2;
}
public override string ToString()
{
return string.Format("Name: \"{0}\" Value: {1}", Name, Value);
}
}
class Program
{
static void Main()
{
var items = new MyItem[3];
items[0] = new MyItem
{
Name = "Hello",
Value = 1
};
items[1] = new MyItem
{
Name = "Hello There",
Value = 2
};
items[2] = new MyItem
{
Name = "There",
Value = 3
};
var result = items.Report(x => !x.Name.Contains("Hello") && x.GetHashCode() == 1).ToList();
Debugger.Break();
}
}
}
It's kind of a tricky one, as in, from your example you could always code something to check for specifics and report 'I searched for term x and the object i returned was not in term x'.
I would have though as others suggested though, that this would have been along the lines for 'return me x' then in code, run a query for 'x where x.property = y' and report non matches.
Following this through, I'd imagine the issue would be that in order to generate the list of non matches, your query or object graph would become pretty massive as you'd need your original object either initially include (or to be expanded via lazy loading to include) many permutations to determine the matches or not.
This is kind of the inverse of running a query on the first place where you'd start with an object and sub select based on conditions, you'd want to select and then selectively super select, catching non conditions.
It's an interesting problem, and one that I'd normally address either client side or code wise before getting to a point where and object was returned or not. But I guess the perfect solution would be to return a single solution and perhaps examine it's associations for links.
The links wouldn't be too hard to find a generic "I've not got one of these" type reason, but to give a 'I've got this link, not that link' response would be harder.
You'd need to maybe provide a method based on some form of predicate builder which took a field and search term and returned an appropriate message if things didn't match. In my mind seems like two slightly different problems.
Slightly rambling now, but would be curious to hear any answers to this!...
I think I follow what you mean. What I think you would want to do is perform two queries, one with selection criteria, and one without, then perform a Linq Except on them to determine which items were excluded, then walk that list and determine what criteria caused them to be excluded.
I can't really think of a better way to do it.
Something like this:
var a = db.Trades.Where(z => z.user == x && z.date == y);
var b = a.Where(z => z.TradeCurrency != null && z.TradeUnderlying.Index != null);
var c = a.Except(b);
List<string> reasons;
foreach(var d in c) {
if (d.TradeCurrency == null)
// add reason
... etc..
}
This would perform a single query (which would have several sub-queries) and only return the results that were excluded (rather than trying to return all results which could be quite large). Unless of course you have a million excluded records and only a few included ones.
Not sure how efficient this is, though compared to a way I can't think of.
EDIT:
I think you are forgetting that Linq queries do not execute until you call an operation that realizes them. In this example, the database is only hit once, even though there are several linq query objects here. The expression tree is modified without executing the queries.
So in this example, when the foreach() occurs, a single database query (with several sub-queries) is executed.
I am having a bit following the "a method should only do one thing"
I have a car text file, and if it contains even one BMW I want to set isValid to true, but while I am going through the text file anyways I thought I would also populate two list high end models(M3,M5 etc) and lower model (335, X3 etc).
I know that method should only do one thing, but it seems so convenient for it to also populate the lists. Here is what I have:
private bool hasBMWegments()
{
foreach (ClassLib.CarSegment carElement in CarSegmentFactory.ContainsCar("BMW"))
{
isValid = true;
if (carElement.Class.IndexOfAny(lowerModels) == 0)
{
lstOlderSegment.Add(carElement.ElementNumber);
}
if (carElementClass.IndexOfAny(upperModels) == 0)
{
lstNewerSegment.Add(carElement.ElementNumber);
}
}
return isValid;
}
Should I just create a method that performs the foreach check again? Or should I create another method inside that method (I would think that would be messy, and wouldn't related to the method name)
edit: sorry working with framework 2.0
I find that code to be a mess compared to this:
private IEnumerable<ClassLib.CarSegment>
GetModels(IEnumerable<ClassLib.CarSegment> segments, string modelID)
{
return segments.Where(x => x.Class.IndexOfAny(modelID) == 0);
}
// ...
var bmwSegments = CarSegmentFactory.ContainsCar("BMW").ToArray();
bool isValid = bmwSegments.Any();
var olderModelSegments = GetModels(bmwSegments, lowerModels);
var newerModelSegments = GetModels(bmwSegments, upperModels);
This code is obviously correct at a glance. The other code makes you look twice at the loop to figure out what's going on.
It looks like all you're doing is setting isValid to true on the first pass through the foreach. So all isValid really means is "is there at least one element?".
In which case you do not need to iterate twice. You can use Any() to do the valid check:
bool IsValid(IEnumerable<CarSegment> elements)
{
return elements.Any();
}
void PopulateSegments(IEnumerable<CarSegment> elements)
{
foreach(var element in elements)
{
//add to lists
}
}