Can the various extension methods be changed to allow the FireAndForget call in the unit test below to be more elegant than I have it?
using System;
using System.Threading.Tasks;
namespace MyNamespace
{
public static class AsyncAdditions
{
private static async Task FireAndForgetInternal<T>(Func<Task<T>> task, Action<T> completion) {
T value = await task();
completion(value);
}
public static void FireAndForget<T>(Func<Task<T>> task, Action<T> completion) {
AsyncAdditions.FireAndForgetInternal(task, completion).DoNotAwait();
}
/// <summary>Empty method gets rid of stupid compiler warning</summary>
public static void DoNotAwait(this Task task) {}
}
}
the test:
using System;
using System.Threading.Tasks;
using NUnit.Framework;
using MyNamespace;
namespace MyTests
{
[TestFixture()]
public class AsyncTests
{
public async Task<int> GetAsyncInteger()
{
return await Task.Factory.StartNew(() => 6);
}
public int MyNumber { get; set;}
public void SlowSynchronousJob() {
for (int i = 0; i < 1E7; i++) {
}
}
[Test()]
public void TestSetter() {
AsyncAdditions.FireAndForget(this.GetAsyncInteger, n => this.MyNumber = n);
this.SlowSynchronousJob();
Assert.AreEqual(6, this.MyNumber);
}
}
}
Related
I'm writing a simple code analyzer and fixer using the Microsoft template. I want to fix nested if statements in else statement. Example:
using System;
using System.Runtime.InteropServices;
namespace ExamApp
{
public class Program
{
static void Main()
{
if (Condition())
{
Action();
}
else
{
if (Condition())
{
Action();
}
}
}
static bool Condition()
{
return false;
}
static void Action() { }
}
}
Should be converted to
using System;
using System.Runtime.InteropServices;
namespace ExamApp
{
public class Program
{
static void Main()
{
if (Condition())
{
Action();
}
else if (Condition())
{
Action();
}
}
static bool Condition()
{
return false;
}
static void Action() { }
}
}
I run Analyzer.Vsix that opens another VS window, opened some sandbox project, wrote code from 1-st example. VS showed me warining in the correct place, sugessted to fix it and fixed it correctly. I decided to write a test like this:
//Diagnostic and CodeFix both triggered and checked for
[TestMethod]
public async Task TestMethod2()
{
var test = #"
using System;
using System.Runtime.InteropServices;
namespace ExamApp
{
public class Program
{
static void Main()
{
if (Condition())
{
Action();
}
else
{
if (Condition())
{
Action();
}
}
}
static bool Condition()
{
return false;
}
static void Action() { }
}
}";
var fixtest = #"
using System;
using System.Runtime.InteropServices;
namespace ExamApp
{
public class Program
{
static void Main()
{
if (Condition())
{
Action();
}
else if (Condition())
{
Action();
}
}
static bool Condition()
{
return false;
}
static void Action() { }
}
}";
var expected = VerifyCS.Diagnostic("AnalyzerTemplate").WithSpan(17, 13, 17, 17).WithArguments("IfKeyword");
await VerifyCS.VerifyCodeFixAsync(test,expected, fixtest);
}
But something went wrong and this is output:
Assert.Fail failed. Context: Iterative code fix application
content of '/0/Test0.cs' did not match. Diff shown with expected as baseline:
using System;
using System.Runtime.InteropServices;
namespace ExamApp
{
public class Program
{
static void Main()
{
if (Condition())
{
Action();
}
else if (Condition())
{
Action();
}
}
static bool Condition()
{
return false;
}
static void Action() { }
}
}
at Microsoft.CodeAnalysis.Testing.Verifiers.MSTestVerifier.Fail(String message) in /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Testing.Verifiers.MSTest/MSTestVerifier.cs:line 78
at Microsoft.CodeAnalysis.Testing.IVerifierExtensions.EqualOrDiff(IVerifier verifier, String expected, String actual, String message) in /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/Extensions/IVerifierExtensions.cs:line 56
at Microsoft.CodeAnalysis.Testing.CodeFixTest`1.VerifyFixAsync(String language, ImmutableArray`1 analyzers, ImmutableArray`1 codeFixProviders, SolutionState oldState, SolutionState newState, Int32 numberOfIterations, Func`10 getFixedProject, IVerifier verifier, CancellationToken cancellationToken) in /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs:line 415
at Microsoft.CodeAnalysis.Testing.CodeFixTest`1.VerifyFixAsync(SolutionState testState, SolutionState fixedState, SolutionState batchFixedState, IVerifier verifier, CancellationToken cancellationToken) in /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs:line 372
at Microsoft.CodeAnalysis.Testing.CodeFixTest`1.RunImplAsync(CancellationToken cancellationToken) in /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.CodeFix.Testing/CodeFixTest`1.cs:line 248
at Microsoft.CodeAnalysis.Testing.AnalyzerTest`1.RunAsync(CancellationToken cancellationToken) in /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/AnalyzerTest`1.cs:line 180
at AnalyzerTemplate.Test.CSharpCodeFixVerifier`2.VerifyCodeFixAsync(String source, DiagnosticResult[] expected, String fixedSource) in C:\JetBrains\C#\AnalyzerTemplate-master\AnalyzerTemplate\AnalyzerTemplate.Test\Verifiers\CSharpCodeFixVerifier`2.cs:line 58
at AnalyzerTemplate.Test.CSharpCodeFixVerifier`2.VerifyCodeFixAsync(String source, DiagnosticResult expected, String fixedSource) in C:\JetBrains\C#\AnalyzerTemplate-master\AnalyzerTemplate\AnalyzerTemplate.Test\Verifiers\CSharpCodeFixVerifier`2.cs:line 46
at AnalyzerTemplate.Test.AnalyzerTemplateUnitTest.TestMethod2() in C:\JetBrains\C#\AnalyzerTemplate-master\AnalyzerTemplate\AnalyzerTemplate.Test\AnalyzerTemplateUnitTests.cs:line 89
at Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.ThreadOperations.ExecuteWithAbortSafety(Action action)
I can't understand, why there are no differences (usually it marks them with +/-) and how to make my test work correctly
The difference is going to be an end of line (\r\n vs \n).
The testing library was recently updated to show CRLF vs LF differences.
You'll need to use a newer package of the testing library that includes the fix from this PR.
I want to refactor (add a prefix) local declared methods and their usage in .cs files
What is the best practice to accomplish that ?
My current code only deals with declarations
using System;
using System.IO;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace CodeScanner {
internal sealed class Fixer : CSharpSyntaxRewriter {
public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) {
base.VisitInvocationExpression(node);
// replace usages
return node;
}
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) {
base.VisitMethodDeclaration(node);
return node.ReplaceNode(node, SyntaxFactory.MethodDeclaration(
node.AttributeLists,
node.Modifiers,
node.ReturnType,
node.ExplicitInterfaceSpecifier,
SyntaxFactory.Identifier("prefix_" + node.Identifier.Value),
node.TypeParameterList,
node.ParameterList,
node.ConstraintClauses,
node.Body,
node.ExpressionBody));
}
}
class Program {
static void Main(string[] args) {
var tree = CSharpSyntaxTree.ParseText(File.ReadAllText("./test.cs"));
var rewriter = new Fixer();
var result = rewriter.Visit(tree.GetRoot());
Console.WriteLine(result.ToFullString());
}
}
}
Input file
using System;
namespace TopLevel
{
class Bar {
public void test1(){}
public void test2(){ Console.WriteLine("str"); }
public void Fizz() {
Console.WriteLine(test1());
Console.WriteLine(test1(test2()));
test2();
}
}
}
Output
using System;
namespace TopLevel
{
class Bar {
public void prefix_test1(){}
public void prefix_test2(){ Console.WriteLine("str"); }
public void prefix_Fizz() {
Console.WriteLine(test1());
Console.WriteLine(test1(test2()));
test2();
}
}
}
Desired output (changes # Fizz ):
using System;
namespace TopLevel
{
class Bar {
public void prefix_test1(){}
public void prefix_test2(){ Console.WriteLine("str"); }
public void prefix_Fizz() {
Console.WriteLine(prefix_test1());
Console.WriteLine(prefix_test1(prefix_test2()));
prefix_test2();
}
}
}
I wrote some code that matches the requirements you set.
See on .NET Fiddle
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using static Globals;
tree = CSharpSyntaxTree.ParseText(File.ReadAllText("Test.cs"));
compilation = CSharpCompilation.Create("HelloWorld").AddSyntaxTrees(tree);
model = compilation.GetSemanticModel(tree);
new Finder().Visit(tree.GetRoot());
Console.WriteLine(new Rewriter().Visit(tree.GetRoot()).NormalizeWhitespace().ToFullString());
public static class Globals
{
public static SyntaxTree tree;
public static CompilationUnitSyntax root;
public static CSharpCompilation compilation;
public static SemanticModel model;
public static Dictionary<IMethodSymbol, string> renames = new();
}
public sealed class Finder : CSharpSyntaxWalker
{
public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
base.VisitMethodDeclaration(node);
renames.Add(model.GetDeclaredSymbol(node), "prefix_" + node.Identifier.Value);
}
}
public sealed class Rewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax mds)
{
IMethodSymbol symbol = model.GetDeclaredSymbol(mds);
mds = (MethodDeclarationSyntax)base.VisitMethodDeclaration(mds);
if (renames.TryGetValue(symbol, out string newName))
mds = mds.ReplaceToken(mds.Identifier, SyntaxFactory.Identifier(newName));
return mds;
}
[return: NotNullIfNotNull("node")]
public override SyntaxNode Visit(SyntaxNode node)
{
node = base.Visit(node);
if (node is SimpleNameSyntax sns &&
model.GetSymbolInfo(sns) is { Symbol: IMethodSymbol ms } && renames.TryGetValue(ms, out string newName)
)
node = sns.ReplaceToken(sns.Identifier, SyntaxFactory.Identifier(newName));
return node;
}
}
I have attribute class
[AttributeUsage(AttributeTargets.Method)]
public class MethodGetterAttribute : ExportAttribute
{
}
I'm using it in method of several namespaces:
namespace Model.First
{
public class PersonBL
{
[MethodGetter]
public void GetName(Person person)
{
}
}
}
namespace Model.First.Second
{
public class PersonBL
{
[MethodGetter]
public void GetName(Person person)
{
}
}
}
namespace Model.First.Second.Third
{
public class WorkerBL
{
[MethodGetter]
public void GetName(Worker worker)
{
}
}
}
I want to order all methods and run it one by one. To get methods I'm doing this:
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(assemblies.FirstOrDefault(a => a.GetName().Name.Contains("Model"))));
var container = new CompositionContainer(catalog);
var importedMethods = container.GetExports<Action<Worker>>() as IEnumerable<Lazy<Action<Worker>>>;
var result = importedMethods.Select(a => a.Value.Target).ToList();// Here i'm getting only worker's method
But it returns only Worker's method. How can I get all three methods from worker?
Well...
Let's create 4 class libraries
Zero.dll with all classes used in other assemblies
using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
namespace Zero
{
[AttributeUsage(AttributeTargets.Method)]
public class MethodGetterAttribute : ExportAttribute { }
public class Person { }
public class Worker : Person { }
public static class MethodHelper
{
public static string GetMethod()
{
var method = new StackTrace().GetFrame(1).GetMethod();
return $"{method.DeclaringType.FullName} {method}";
}
}
public static class Discovery
{
public static TDelegate[] GetDelegates<TAttribure, TDelegate>()
where TAttribure : Attribute
where TDelegate : Delegate
{
return Directory.GetFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "*.dll")
.Select(file => { try { return Assembly.LoadFrom(file); } catch { return null; } })
.OfType<Assembly>()
.Append(Assembly.GetEntryAssembly())
.SelectMany(assembly => assembly.GetTypes())
.SelectMany(type => type.GetMethods())
.Where(method => method.GetCustomAttributes(typeof(TAttribure)).Any())
.Select(method => Delegate.CreateDelegate(typeof(TDelegate), null, method, false))
.OfType<TDelegate>()
.ToArray();
}
}
}
Model.First.dll referencing Zero.dll
using System;
using Zero;
namespace Model.First
{
public class PersonBL
{
[MethodGetter]
public void GetName(Person person)
{
Console.WriteLine(MethodHelper.GetMethod());
}
}
}
Model.First.Second.dll referencing Zero.dll
using System;
using Zero;
namespace Model.First.Second
{
public class PersonBL
{
[MethodGetter]
public void GetName(Person person)
{
Console.WriteLine(MethodHelper.GetMethod());
}
[MethodGetter]
public void Incompatible(string s)
{
Console.WriteLine(MethodHelper.GetMethod());
}
}
}
Model.First.Second.Third.dll referencing Zero.dll
using System;
using Zero;
namespace Model.First.Second.Third
{
public class WorkerBL
{
[MethodGetter]
public void GetName(Worker worker)
{
Console.WriteLine(MethodHelper.GetMethod());
}
public void NoAttribute(Worker worker)
{
Console.WriteLine(MethodHelper.GetMethod());
}
}
}
Then let's create console application ConsoleApp.exe referencing Zero.dll, Model.First.dll, Model.First.Second.dll and Model.First.Second.Third.dll
using System;
using Zero;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
var worker = new Worker();
foreach (var d in Discovery.GetDelegates<MethodGetterAttribute, Action<Worker>>())
d.Invoke(worker);
}
}
public class WorkerBL
{
[MethodGetter]
public void GetName(Worker worker)
{
Console.WriteLine(MethodHelper.GetMethod());
}
}
}
Let's create Junk.txt, put some nonsense like bd%E56#EVwD into it, rename the file to Junk.dll and add it into .exe file directory and then start the application.
Output is:
Model.First.PersonBL Void GetName(Zero.Person)
Model.First.Second.PersonBL Void GetName(Zero.Person)
Model.First.Second.Third.WorkerBL Void GetName(Zero.Worker)
ConsoleApp.WorkerBL Void GetName(Zero.Worker)
As expected. It finds all compatible methods with specified attribute and returns delegates for them.
I would like to convert a blocking IEnumerable (possibly infinite) into messages sent to an Actor. What is the best way to do this? I am currently attempting to create a Task within an actor on PreStart and inside the task have it send messages to but it doesn't seem to be working.
I've read some pages about preferring to use PipeTo to wrap a Task but that seems to only be used to retrieve a single result rather than have a separate process continually sending values.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Akka.Actor;
namespace Junk
{
public class Program
{
public static void Main()
{
var system = ActorSystem.Create("my-system");
var actor = system.ActorOf(Props.Create(() => new Manager()));
Console.ReadLine();
}
}
public class Manager : ReceiveActor
{
private Task _task;
public Manager() {
Receive<uint>(msg => { Console.WriteLine($"received {msg}"); });
}
protected override void PreStart() {
Console.WriteLine($"{Self} - PreStart --------------");
startTask();
}
private void startTask() {
_task = Task.Factory.StartNew(() => {
BlockingEnumerable source = new BlockingEnumerable();
Console.WriteLine($"task starting loop -------------");
foreach (uint v in source) {
Self.Tell(v);
}
});
}
}
public class BlockingEnumerable : IEnumerable<uint>
{
public IEnumerator<uint> GetEnumerator() { return new BlockingEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
public class BlockingEnumerator : IEnumerator<uint>
{
private uint value = 0;
public uint Current => value;
object IEnumerator.Current => Current;
public void Dispose() { }
public bool MoveNext() { Thread.Sleep(2000); value += 1; return true; }
public void Reset() { value = 0; }
}
}
I need to get MethodInfo for method called in Action delegate in order to check, whether methods called in Action has MyCustomAttibute
public void Foo( Action action )
{
if(Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
{
throw new ArgumentException("Invalid action");
}
}
The Foo method should be able to be called as following:
Foo(() =>
{
instanceOfFooClass.Method1().Method2();
});
In Foo method I want to be sure that Method1 and Method2 has MyCustomAttribute. However action.Method is giving me the MethodInfo, which is the action of delegate, which happens when using lambda expression. Is there any way to get Method1 and Method2 MethodInfo?
As mentioned in the comments, Expression<T> is probably the best way to achieve this. However, it requires a Compile() at runtime so it should be performance profiled.
With Expression<T> you can easily get access to Method info like this:
public MethodInfo GetMethodInfo(Expression<Action> action)
{
return ((MethodCallExpression)action.Body).Method;
}
But, before executing the action you must do this:
private void InvokeMethod(Expression<Action> action)
{
action.Compile().Invoke();
}
EDIT
Ah yes, I forgot how to get access to the customer attribute. You would do it like this:
var methodInfo = ((MethodCallExpression)myAction.Body).Method;
var attributes = methodInfo.GetCustomAttributes<T>(true);
EXAMPLE
Here is an example showing passing chained method calls to Expression<Action>:
public class ActionTest
{
public void DoAction(Action action)
{
action();
}
public void DoExpressionAction(Expression<Action> action)
{
var method2Info = ((MethodCallExpression)action.Body).Method;
// a little recursion needed here
var method1Info = ((MethodCallExpression)((MethodCallExpression)action.Body).Object).Method;
var myattributes2 = method2Info.GetCustomAttributes(typeof(MyAttribute), true);
var myattributes1 = method1Info.GetCustomAttributes(typeof(MyAttribute), true);
action.Compile().Invoke();
}
}
[AttributeUsage(AttributeTargets.Method)]
public class MyAttribute : Attribute
{
private string message;
public MyAttribute(string message)
{
this.message = message;
}
}
public class MethodTest
{
[MyAttribute("Number1")]
public MethodTest Method1()
{
Console.WriteLine("Action");
return this;
}
[MyAttribute("Number2")]
public MethodTest Method2()
{
Console.WriteLine("ExpressionAction");
return this;
}
}
class Program
{
static void Main(string[] args)
{
ActionTest target = new ActionTest();
MethodTest instance = new MethodTest();
target.DoExpressionAction(() => instance.Method1().Method2() );
Console.ReadLine();
}
static void Method1()
{
Console.WriteLine("Action");
}
static void Method2()
{
Console.WriteLine("ExpressionAction");
}
}
If you call your Foo() methdod like this:
Foo(instanceOfFooClass.Method);
Your code works as you'd expect (void methods are actions, after all).
On a side note, I think "chaining" method calls in fact counts as you're only passing the last one through.
Full sample demonstrating the behavior:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication4
{
class MyCustomAttribute : Attribute { }
class FooClass
{
[MyCustom]
public void DecoratedMethod() { Console.WriteLine("Decorated Method - executed."); }
public void NotDecoratedMethod() { Console.WriteLine("Not Decoreated Method - executed."); }
}
class Program
{
static void Main(string[] args)
{
FooClass instanceOfFooClass = new FooClass();
Foo(instanceOfFooClass.DecoratedMethod);
Foo(instanceOfFooClass.NotDecoratedMethod);
Console.ReadLine();
}
public static void Foo(Action action)
{
if (Attribute.GetCustomAttributes(action.Method, typeof(MyCustomAttribute)).Count() == 0)
Console.WriteLine(string.Format("Invalid method {0}", action.Method.Name));
else
{
Console.WriteLine(string.Format("Valid method {0}", action.Method.Name));
action.Invoke();
}
}
}
}