I have this code:
int pictureId=10;
string cacheKey = string.Format(ModelCacheEventConsumer.PICTURE_URL_MODEL_KEY, pictureId);
return _cacheManager.Get(cacheKey, () =>
{
var url = _pictureService.GetPictureUrl(pictureId, showDefaultPicture: false);
//little hack here. nulls aren't cacheable so set it to ""
if (url == null)
url = "";
return url;
});
What exactly this part of code means:"
() =>
{"
var url =...."
Does it mean that function, which returns URL, is executed for every row from cache? What is then return type - list?
URL of documentation of this syntax?
Second parameter to _cacheManager.Get() method is an anonymous method that captures pictureId and among other things.
https://msdn.microsoft.com/en-us/library/bb397687.aspx
C# Lambda expressions: Why should I use them?
To figure out the returned type, try using var keyword and creating a local variable: instead of return _cacheManager.Get() write var x = _cacheManager.Get() followed by return x. Then simply hover over the keyword var in Visual Studio.
What exactly this part of code means
It's just passing a method by parameter.
Does it mean that function, which returns URL, is executed for every row from cache?
Only the content of the method Get of the object _cacheManager can answer this.
What is then return type - list?
The return type is a string, since your variable url is a string.
What exactly this part of code means:
Well, lambda expression is a "shortcut" for delegate, and delegate is a reference to a callback function (in a very simple explanation). So this is a function which will be called inside your Get method of cache manager, which expects to have a Func delegate as a second param
Does it mean that function, which returns URL, is executed for every row from cache?
I think it will executes for row which has a key value the same as the value of cacheKey variable.. So, only one time (if keys are unique)
What is then return type - list?
The return type is string, because if result of GetPictureUrl is null it returns empty string. And calling this method is expecting to have a string in a result also
Related
I am trying to get the parameters list of a class method using Roslyn and noticed a strange behavior that Roslyn considers and returns a Lambda parameter used inside the body of the method as as one of the parameters of the method, which cause an error in my code. Why does Roslyn consider a lambda parameter as of the method's parameters?
Here is the code:
var paramDeclaratons = memmeth.DescendantNodes().OfType<ParameterSyntax>();
foreach (var mempara in paramDeclaratons)
{
String paramType = mempara.Type.ToFullString().Trim(); //Here it crashes with System.NullReferenceException because Lambda returns no type!
The code which is parsed:
public void Method1(RequestId requestId)
{
...
var packetsToKeep = this.queuedPackets.Where(p => p.RequestId != requestId)
p is returned as one of the parameters of Method1 with no type
Assuming memmeth is a MethodDeclarationSyntax, then what you want is to access its ParameterList.Parameters:
var paramDeclaratons = memmeth.ParameterList.Parameters;
I am using Moq to mock some interface. Here it is:
var titleGenerator = new Mock<ITitleGenerator>();
titleGenerator.Setup(t => t.GenerateTitle()).Returns(Guid.NewGuid().ToString);
Console.WriteLine(titleGenerator.Object.GenerateTitle());
Console.WriteLine(titleGenerator.Object.GenerateTitle());
It prints the same value twice. But if I replace the second line with this:
titleGenerator.Setup(t => t.GenerateTitle()).Returns(() => Guid.NewGuid().ToString());
it returns unique values on each call.
I always thought method groups are just a shortcut to lambda expression. Is there any difference? I tried searching the documentations for any explanation. Can someone enlighten me?
It looks like the method group evaluates the expression once and somehow caches it? Or does it have something to do with Moq?
In your first example, you're passing the ToString function of a single Guid, which then gets called on every invocation. It's equivalent to this:
Guid guid = Guid.NewGuid();
titleGenerator.Setup(t => t.GenerateTitle()).Returns(guid.ToString)
In your second example, you're passing a function that first creates a new Guid and then invokes ToString() on it.
The difference is in the inputs. In the first case the "method group" is actually a delegate for Guid.ToString. But since it requires an instance as "input", the instance is part of the delegate expression, and so the same "input" is used each time.
It would be equivalent to:
var titleGenerator = new Mock<ITitleGenerator>();
Guid g = Guid.NewGuid();
titleGenerator.Setup(t => t.GenerateTitle()).Returns(g.ToString);
In the second case, the delegate has no input. The Guid instance is calculated within the delegate, so a new Guid is used each time.
For an equivalent example that might be easier to understand, the code:
var id = 1;
Func<string> f = id.ToString;
id = 2;
Console.WriteLine(f()); // 1
will write "1", whereas:
var id = 1;
Func<string> f = () => id.ToString();
id = 2;
Console.WriteLine(f()); // 2
will write "2".
In the first case, the delegate (Func<> instance) f is created with the value 1 as Target and the method info for string int.ToString() as Method. The later reassignment to id does not affect f.
In the second case, things will be more indirect. The compiler will generate a new method that corresponds to the => arrow. The local variable id is captured or closed over (is in the closure of the lambda). That means, behind the scenes, id is really promoted to a field somewhere (compiler's choice). When your method mentions id, it really accesses that field. And the compiler-generated method corresponding to the => arrow also reads that field. Now the Func<> is created with its Method property being this compiler-generated method. Because of all this, the result will be "2" here. That is the closure semantics of anonymous functions in C#.
Your original Moq example is just the same. The Returns overload in question takes an argument Func<TResult> valueFunction where TResult is string in your use. That valueFunction is what I called f in my simpler example.
I was reading some code and saw the following:
Method.Find(delegate(Department depts) {
return depts.Id == _departmentId; });
The T Find method has the following description:
public T Find(Predicate<T> match);
// Summary:
// Searches for an element that matches the conditions defined by the specified
// predicate, and returns the first occurrence within the entire
// System.Collections.Generic.List<T>.
//
// Parameters:
// match:
// The System.Predicate<T> delegate that defines the conditions of the element
// to search for.
// (...)
Is it possible to rewrite this method to take a lambda expression as a parameter, and if so, how?
The method can already accept a lambda expression as a parameter, if you want to pass one to it.
The method simply indicates that it accepts a delegate. There are several ways of defining a delegate:
A lambda (Find(a => true))
An anonymous delegate (what you used in your example)
A method group Find(someNamedMethod)
Reflection (Find((Predicate<Whatever>)Delegate.CreateDelegate(typeof(SomeClass), someMethodInfo)))
No need to re-write the method, you can use a lambda already, as below:
Method.Find(x => x.Id == _departmentId );
The code you provide is an anonymous delegate
Method.Find(delegate(Department depts) {
return depts.Id == _departmentId; });
a lambda is an anonymous function.
I have a failing test in NSubstitute because a parameter passed in to a substituted call does not match. Here is the relevant code that is being tested:
// Arrange
PermissionsProviderSub = Substitute.For<IPermissionsProvider>();
MenuDataProviderSub = Substitute.For<IMenuDataProvider>();
PermissionsProviderSub.GetPermissions(UserId).Returns(ExpectedUserPermissions);
MenuDataProviderSub.GetMenuData(ExpectedUserPermissions.AuthorisedPageIds).Returns(Arg.Any<IList<BusinessFocusArea>>());
var sut = new MenuViewModelFactory(MenuDataProviderSub, PermissionsProviderSub);
// Act
var result = sut.Create();
// Assert
MenuDataProviderSub.Received().GetMenuData(ExpectedUserPermissions.AuthorisedPageIds);
The problem occurs in the ExpectedUserPermissions.AuthorisedPageIds property, which looks like this:
public IEnumerable<string> AuthorisedPageIds
{
get
{
return ApplicationPagePermissions != null ?
ApplicationPagePermissions.Select(permissionSet => permissionSet.PageId) :
Enumerable.Empty<string>();
}
}
As you can see, there is a LINQ Select, which is extracting the PageId property from within the ApplicationPagePermissions collection and returning it as an IEnumerable<string>. Because the projection within that property creates a new object, the substitution does not match, as it sees the 2 objects as being different.
Can I create a callback on the parameter passed in to GetMenuData so that I can examine the value of it?
The documentation on NSubstitute callbacks only talks about examining the return value from a call, rather than a parameter passed into the call.
Typical. As soon as I post to SO, the answer presents itself. Rather than expecting a specific object when creating the substitute call, I expect any instance of type IEnumerable<string> and create a callback when checking the Received() call that actually verifies the values. The substitute call becomes this:
MenuDataProviderSub.GetMenuData(Arg.Any<IEnumerable<string>>()).Returns(Arg.Any<IList<BusinessFocusArea>>());
The Received() check becomes this:
MenuDataProviderSub.Received().GetMenuData(Arg.Is<IEnumerable<string>>(a => VerifyPageIds(ExpectedUserPermissions.AuthorisedPageIds, a)));
private static bool VerifyPageIds(IEnumerable<string> expected, IEnumerable<string> actual)
{
var expectedIds = expected.ToList();
var actualIds = actual.ToList();
return expectedIds.Count == actualIds.Count && expectedIds.All(actualIds.Contains);
}
If anyone is very familar with the Linq.Dynamic namespace I could use some help -- couldn't find any indepth resources on the internet.
Basically I'm using DynamicExpression.ParseLambda to create an expression where the type is not known at compile time,
public Expression GetExpression(Type t, List<QueryFilter> filters)
{
// pseudo code
// extracts a string representation of the query as 'expressionString'
return DynamicExpression.ParseLambda(t, typeof(Boolean), expressionString, values);
}
Where a QueryFilter is:
public class QueryFilter
{
string propertyName;
ExpressionType operationType;
object value;
}
Which represents a simple binary function like "Age > 15" or something.
This is how the 'GetExpression' function works, it takes 2 types -- one that is the input type and one that is the output type, and ultimately generates what would normally be created with a Func delegate. It also takes a string that represents the query and a params object[] of values, which are 'expressionString' and 'values' above, respectively.
However I am having trouble executing the dynamic expression in LINQ-to-SQL, using a DataContext generated from SqlMetal (.dbmc file).
DatabaseContext db = new DatabaseContext(connectionString);
var filter = DynamicExpressionBuilder.
GetExpression(typeof(SysEventLogT), sysEventFilters)
var query = db.SysEventLogT.Where(filter);
Produces the following error,
System.Data.Linq.Table<DBReporting.Linq.Data.SysEventLogT>
does not contain a definition for 'Where' and the best extension method overload
System.Linq.Dynamic.DynamicQueryable.Where<T>(System.Linq.IQueryable<T>, string, params object[])
has some invalid arguments.
I know that my DataContext instance actually treats the sql tables as properties...do I need to reflect with GetProperty() somehow for this to work? Or perhaps I need to create another .Where extension?
Your GetExpression is returning an Expression type - the DynamicQueryable.Where method, when used as an extension method, expects a string as the first parameter.
You need your call to Where to look like this:
var query = db.SysEventLogT.Where("Age > #0", 15);
Also, you could try the following, just to be explicit:
var query = db.SysEventLogT.AsQueryable().Where("Age > #0", 15);
Note that if easier, you can build a sting containing the full filter and not use the params object[] parameter at all:
var query = db.SysEventLogT.AsQueryable().Where("Age > 15");