I have written a method below like this:
internal static IList<EmpowerTaxView> GetEmpowerTaxViewsByLongAgencyAndAgencyTaxTypes(
IList<EmpowerCompanyTaxData> validEmpowerCompanyTaxDatas,
IList<EmpowerTaxView> empowerTaxViews)
{
IList<EmpowerTaxView> result = new List<EmpowerTaxView>();
foreach (EmpowerCompanyTaxData empowerCompanyTaxData in validEmpowerCompanyTaxDatas)
{
IList<EmpowerTaxView> validEmpowerTaxViews =
GetEmpowerTaxViewsByLongAgencyAndTaxType(
empowerCompanyTaxData, empowerTaxViews);
validEmpowerTaxViews.ToList().ForEach(delegate(EmpowerTaxView etv)
{
result.Add(etv);
});
}
return result;
}
And for this method, the resharper says:
validEmpowerTaxViews.ToList().ForEach(delegate(EmpowerTaxView etv)
{
result.Add(etv);
});
Convert to Method Group. What does this mean and what should be done to get rid of this.
What Resharper means is that you can express the ForEach code more simply by using the method group Add.
Example:
validEmpowerTaxViews.ToList().Foreach(result.Add);
The method group defined by Add is compatible with the delegate expected by ForEach and hence the C# compiler will take care of doing the conversion. The default in Resharper is to prefer method groups over lambdas and explicit delegate creation statements.
JaredPar already provided the correct answer, I just wanted to suggest a simpler implementation of the method:
internal static IList<EmpowerTaxView> GetEmpowerTaxViewsByLongAgencyAndAgencyTaxTypes(
IList<EmpowerCompanyTaxData> validEmpowerCompanyTaxDatas,
IList<EmpowerTaxView> empowerTaxViews)
{
var results =
from empowerCompanyTaxData in validEmpowerCompanyTaxDatas
from etv in GetEmpowerTaxViewsByLongAgencyAndTaxType(
empowerCompanyTaxData, empowerTaxViews)
select etv;
return results.ToList();
}
Accept Resharper's suggestion to see what changes it makes. You can always undo them.
If you aren't happy with the change and don't want Resharper suggesting it in future then you can disable that specific option - the others will remain available. See the answer here for details.
Resharper: vars
From Microsoft website Method group is a set of overloaded methods resulting from a member lookup
You can check inspecting MSIL code that if you use the method group then it just makes a new delegate pointing to that method.
But if you use a lambda expression then it generates a class with anonymous method under the hood. The result is that method group is required less memory then lambda and Resharper suggests you to optimize
Related
I'm creating code by using CodeDom. However, CodeDom does not support lambda statements. So I'm now trying to mimic a lambda statement by creating a local method and pass on the method as a parameter to another method. Like so:
public string MainMethod(string myParameter)
{
string g() { return instance.MainMethod(myParameter); }
return someOtherMethod(g);
}
The method 'MainMethod' is already generated by using CodeDom
and I'm trying to get the local method in there. However, I cannot find a way to do that up to this point. I could use some help with that.
I already tried adding a CodeMemberMethod to a CodeMemberMethod but there seems to be no way to do that. I cannot seem to find any alternatives.
Currently my CodeDom code is using MethodInfo as a base:
var method = new CodeMemberMethod();
method.Name = methodInfo.Name;
method.ReturnType = new CodeTypeReference(methodInfo.ReturnType);
//left out parameter stuff
var gMethod = new CodeMemberMethod() { Name = "g", ReturnType = new CodeTypeReference(methodInfo.ReturnType) };
gMethod.Statements.Add(new CodeMethodReturnStatement(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeVariableReferenceExpression("instance"), methodInfo.Name), parameterReferences.ToArray())));
method.Statements.Add(gMethod);
Now, the pain is in the last statement. I'm actually trying to add a CodeMemberMethod to a CodeMemberMethod, which is not allowed via the Statements property. Is there any way to do that in another way?
Local functions were not a supported language construct until C# version 7. CodeDOM was designed much earlier and does not cover all C# feature, even of the then-current version of C#. In other words, there is, unfortunately, no way to declare a “local method” and add it to the Statements collection of another method.
Instead, consider declaring a separate private method. Your class's public interface will remain unaffected and, most likely, you will achieve what you want. However, no implicit access to the 'outer method's' parameters will be possible.
Also, consider looking at this answer for further ideas.
in a for loop I receive results from a db as dynamic type
dynamic {system.collections.generic.List<object>}
I need to collect these results into one single variable.
I tried defining a variable
dynamic results = new List<object>();
and then
var queryResults = _dbManager.Query(query);
results = results.Concat(queryResults);
but I have this exception:
System.Collections.Generic.List<object> does non contain a definition for 'Concat'
I can't find a solution. Do you how can I do this? Thanks!
The problem is that dynamic types and extension methods don't work well together (read the explanation of Eric Lippert on the why). You have to call the extension method yourself as a static method (which it actually is):
var l = Enumerable.Concat(results, queryResults);
Concat is an extension method. Extension methods are a compiler syntactic sugar. Essentially the compiler chooses the appropriate static method to call based on the static type of the object on which you call the extension method. But dynamic variable have no static type so the compiler cannot search for extension methods.
Edit: Patrick Hofman's solution should work, but it is not LINQ that does not work well with extension methods. In fact LINQ is heavily relying on extension methods. The problem is LINQ assumes static typing of variable (and actually is the very reason to use LINQ: get the compiler validate your code for type safety)
This must be a duplicate but i haven't found it. I've found this question which is related since it answers why it's recommended to use a method group instead of a lambda.
But how do i use an existing method group instead of a lambda if the method is not in the current class and the method is not static?
Say i have a list of ints which i want to convert to strings, i can use List.ConvertAll, but i need to pass a Converter<int, string> to it:
List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(i => i.ToString());
This works, but it creates an unnecessary anonymous method with the lambda. So if Int32.ToString would be static and would take an int i could write:
List<string> strings = ints.ConvertAll<string>(Int32.ToString);
But that doesn't compile - of course. So how can i use a method group anyway?
If i'd create an instance method like this
string FooInt(int foo)
{
return foo.ToString();
}
i could use strings = ints.ConvertAll<string>(FooInt);, but that is not what i want. I don't want to create a new method just to be able to use an existing.
There is an static method in the framework, that can be used to convert any integrated data type into a string, namely Convert.ToString:
List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(Convert.ToString);
Since the signature of Convert.ToString is also known, you can even eliminate the explicit target type parameter:
var strings = ints.ConvertAll(Convert.ToString);
This works. However, I'd also prefer the lambda-expression, even if ReSharper tells you something different. ReSharper sometimes optimizes too much imho. It prevents developers from thinking about their code, especially in the aspect of readability.
Update
Based on Tim's comment, I will try to explain the difference between lambda and static method group calls in this particular case. Therefor, I first took a look into the mscorlib disassembly to figure out, how int-to-string conversion exactly works. The Int32.ToString method calls an external method within the Number-class of the System namespace:
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), SecuritySafeCritical]
public string ToString(IFormatProvider provider)
{
return Number.FormatInt32(this, null, NumberFormatInfo.GetInstance(provider));
}
The static Convert.ToString member does nothing else than calling ToString on the parameter:
[__DynamicallyInvokable]
public static string ToString(int value)
{
return value.ToString(CultureInfo.CurrentCulture);
}
Technically there would be no difference, if you'd write your own static member or extension, like you did in your question. So what's the difference between those two lines?
ints.ConvertAll<string>(i => i.ToString());
ints.ConvertAll(Convert.ToString);
Also - technically - there is no difference. The first example create's an anonymous method, that returns a string and accepts an integer. Using the integer's instance, it calls it's member ToString. The second one does the same, with the exception that the method is not anonymous, but an integrated member of the framework.
The only difference is that the second line is shorter and saves the compiler a few operations.
But why can't you call the non-static ToString directly?
Let's take a look into the ConvertAll-method of List:
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
if (converter == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
}
List<TOutput> list = new List<TOutput>(this._size);
for (int i = 0; i < this._size; i++)
{
list._items[i] = converter(this._items[i]);
}
list._size = this._size;
return list;
}
The list iteraterates over each item, calls the converter with the item as an argument and copys the result into a new list which it returns in the end.
So the only relation here is your converter that get's called explicitly. If you could pass Int32.ToString to the method, the compiler would have to decide to call this._items[i].ToString() within the loop. In this specific case it would work, but that's "too much intelligence" for the compiler. The type system does not support such code conversions. Instead the converter is an object, describing a method that can be called from the scope of the callee. Either this is an existing static method, like Convert.ToString, or an anonymous expression, like your lambda.
What causes the differences in your benchmark results?
That's hard to guess. I can imagine two factors:
Evaluating lambdas may result in runtime-overhead.
Framework calls may be optimized.
The last point especially means, that the JITer is able to inline the call which results in a better performance. However, those are just assumptions of mine. If anyone could clarify this, I'd appreciate it! :)
You hit the nail on the head yourself:
This works, but it creates an unnecessary anonymous method with the
lambda.
You can't do what you're asking for because there is no appropriate method group that you can use so the anonymous method is necessary. It works in that other case because the implicit range variable is passed to the delegate created by the method group. In your case, you need the method to be called on the range variable. It's a completely different scenario.
I'm getting this message from ReSharper. ReSharper is not proposing the change that I think would be appropriate after examining the code. As a result I am concerned that the problem might might be my not understanding what's going on instead of ReSharper not being as helpful as it could be.
public interface IFrobable { }
public class DataClass
{
public List<IFrobable> Frobables {get; set;}
//...
}
public class WorkerClass
{
//...
void Frobinate(List<IFrobable> frobables)
{
//Frobs the input
}
void DoSomething(List<IFrobable> input>)
{
//Original code with Resharper on OfType<IActivity>
Frobinate(input.OfType<IFrobable>().ToList());
//Suggested change from ReSharper - Is this a generic refactor
//instead of issue specific?
Frobinate(Enumerable.OfType<IFrobable>(input).ToList());
//What I think should be safe to do - compiles and appears to work
Frobinate(input);
}
}
Is there any reason why my proposed change might not be safe.
This is a regular function call:
Enumerable.OfType<IFrobable>(input)
This is the same function but invoked as an extension method:
input.OfType<IFrobable>()
In your case:
Frobinate(input);
Is absolutely fine because:
input.OfType<IFrobable>().ToList()
Equals to:
input.Where(x => x as IFrobable != null).ToList()
And in you method input is already defined as List<IFrobable> so what's the point?
Your last case may or may not introduce a logic error.
Do you really want Frobinate the ability to modify the input list passed into DoSomething or just a copy of those references?
//Suggested change from ReSharper
Actually, invoking OfType as a static method on Enumerable rather than as an extension method on input is not a suggestion from ReSharper - it's a context action. I expound on the difference in this post.
To the actual issue:
The inspection
Redundant 'IEnumerable.OfType<T>' call. Consider comparing with 'null' instead
is not one that ReSharper offers a quick fix solution with, I guess since there isn't a single unambiguously 'correct' change to make. It's just saying
hey, everything in input is definitely going to be of type IFrobable - if you're trying to filter this list you might have meant to be filtering by nullness instead
This probably isn't relevant in your case.
As to your proposed fix - as already noted, this will mean passing the actual List<> reference given to DoSomething to Frobinate, rather than a new List<> containing the same items - if this is OK, then go for it.
in your example you have input which already consists of elements of type IFrobable so ReSharper says that it doesn't make sense to filter them by type IFrobable because the filter condition is always true it proposes you to use just input.ToList() invocation or to filter elements buy nullness: input.Where(element => element != null).ToList()
I have a method that alters an "Account" object based on the action delegate passed into it:
public static void AlterAccount(string AccountID, Action<Account> AccountAction) {
Account someAccount = accountRepository.GetAccount(AccountID);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
This works as intended...
AlterAccount("Account1234", a => a.Enabled = false);
...but now what I'd like to try and do is have a method like this:
public static void AlterAccount(string AccountID, string AccountActionText) {
Account someAccount = accountRepository.GetAccount(AccountID);
Action<Account> AccountAction = MagicLibrary.ConvertMagically<Action<Account>>(AccountActionText);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
It can then be used like:
AlterAccount("Account1234", "a => a.Enabled = false");
to disable account "Account1234".
I've had a look at the linq dynamic query library, which seems to do more or less what I want but for Func type delegates, and my knowledge of Expression trees etc isn't quite good enough to work out how to achieve what I want.
Is there an easy way to do what I want, or do I need to learn expressions properly and write a load of code?
(The reason I want to do this is to allow an easy way of bulk updating account objects from a powershell script where the user can specify a lambda expression to perform the changes.)
The Dynamic LINQ library is a fine choice, as it'll generate expressions you can compile to code in a lightweight fashion.
The example you provided actually produces a boolean -- so you should be able to ask for a Func and it might sort it out.
Edit: This of course is wrong, as Expressions don't have assignment in them at all.
So, another potential way is to take two lambdas. One to find the property you want, one to provide a value:
(a => a.AccountId), (a => true)
Then use reflection to set the property referenced in the first lambda with the result of the second one. Hackish, but it's still probably lightweight compared to invoking the C# compiler.
This way you don't have to do much codegen yourself - the expressions you get will contain most everything you need.
You may try this: Dynamic Lambda Expressions Using An Isolated AppDomain
It compiles a lambda expression using CodeDOM compiler. In order to dispose the in-memory assembly that gets created, the compiler runs on an isolated AppDomain. For the passing the expression through the domain boundary, it has to be serialized. Alas, Expression<> is not Serializable. So, a trick has to be used. All the details are explained in the post.
I'm the author of that component, by the way. I would like very much to hear your feedback from it.
There is no general way to parse a string into a lambda expression without a full compilation, because lambda expressions can reference things that are defined outside the lambda expression. I know of no library that handles the specific case you want. There's a long discussion of this on a thread on a C# discussion group.
The easiest way to get what you want is to compile a method at runtime. You can write a function that takes in the string "a.Enabled = true; return a;" and sticks that in the middle of a function that takes an Account as a parameter. I would use this library as a starting point, but you can also use the function mentioned on another thread.
That's easy:
Use CodeDom to generate the module containing the "surrounding class" you'll use to build the expression; this class must implement the interface known to your application
Use CodeSnippedExpression to inject the expression into its member.
Use Activator type to create the instance of this class in runtime.
Basically, you need to build the following class with CodeDom:
using System;
using MyNamespace1;
using ...
using MyNamespace[N];
namespace MyNamespace.GeneratedTypes
{
public class ExpressionContainer[M] : IHasAccountAction
{
public Action<Account> AccountAction {
get {
return [CodeSnippedExpression must be used here];
}
}
}
}
Assuming that IHasAccountAction is:
public IHasAccountAction {
public Action<Account> AccountAction { get; }
}
If this is done, you can get the expression compiled from string with ease. If you need its expression tree representation, use Expression<Action<Account>> instead of Action<Account> in generated type.