Can't dynamically invoke a method in c# - c#

I have a class whose method I want to invoke dynamically. But I am not able to do it. Am I missing something?
public class P_WATER
{
private int[] jDS = new int[20];
private int n;
public int[] JDS { get => jDS; set => jDS = value; }
public int N { get => n; set => n = value; }
public void P_WATER1()
{
//something...
}
}
public class Test
{
P_WATER P_WATERState1 = new P_WATER();
PLibStateList.Add(P_WATERState1);
// Try to invoke methods from each objects.
foreach (object item in StateUtility.PLibStateList)
{
Type objType= item.GetType();
objType.InvokeMember(objType.Name + "1", BindingFlags.InvokeMethod, null, item, null);
}
}
When trying to invoke the method I am getting the following exception:
Could not load file or assembly 'System.Runtime, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
But my assembly is well bound to the project.

I've tried the same code (with little modifications) in VS2019 (Console App) and worked just fine... weird... check the using statements for ambiguity (just in case):
using System;
using System.Collections.Generic;
using System.Reflection;
My full code:
using System;
using System.Collections.Generic;
using System.Reflection;
namespace cant_dynamically_invoke_a_method_in_c_sharp
{
class Program
{
static void Main(string[] args)
{
Test.InvokeStuff();
}
}
public class P_WATER
{
private int[] jDS = new int[20];
private int n;
public int[] JDS { get => jDS; set => jDS = value; }
public int N { get => n; set => n = value; }
public void P_WATER1()
{
//something...
Console.WriteLine("Success!");
}
}
public class Test
{
public static void InvokeStuff()
{
// Needed to mock this up
List<P_WATER> PLibStateList = new List<P_WATER>();
P_WATER P_WATERState1 = new P_WATER();
PLibStateList.Add(P_WATERState1);
// Try to invoke methods from each objects.
foreach (object item in PLibStateList)
{
Type objType = item.GetType();
objType.InvokeMember(objType.Name + "1", BindingFlags.InvokeMethod, null, item, null);
}
}
}
}
Entered the method successfuly:
Regards!

Related

C# method Linq variable return

hope your help :)
I search to make the result of the LinQ Variable bellow "ES" available in an other method.
public void Contract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach(var chain in slice.FutureChains)
{
var ES = (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
I downloaded QuantConnect just to get an idea what you're trying to do. The example below should at least not yield any errors, but I haven't tried the output.
using QuantConnect.Data;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm
{
public interface IFuturesContractSelector_ES
{
FuturesContract GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice);
}
public class Contract_ES : IFuturesContractSelector_ES
{
private readonly Slice _Slice;
private readonly QCAlgorithm _Algorithm_ES;
public Contract_ES(QCAlgorithm Algorithm_ES)
{
_Algorithm_ES = Algorithm_ES;
}
public Contract_ES(Slice slice)
{
_Slice = slice;
}
public FuturesContract GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach (var chain in slice.FutureChains)
{
if (chain.Value.Symbol.Value.StartsWith("ES"))
{
return (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return null;
}
}
}
Or you could do an extension on the Slice class:
using QuantConnect.Data;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm
{
public static class SliceExtensions
{
public static FuturesContract GetFuturesContract_ES(this Slice slice, QCAlgorithm Algorithm_ES)
{
foreach (var chain in slice.FutureChains)
{
if (chain.Value.Symbol.Value.StartsWith("ES"))
{
return (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return null;
}
}
public class Test
{
public void TestMyMethod(Slice slice)
{
var contract = slice.GetFuturesContract_ES(new QCAlgorithm());
//... do something
}
}
}
I tried to create an interface then the method, result is :
using QuantConnect.Securities;
namespace Quant
{
public interface IFuturesContractSelector_ES
{
void GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice);
}
}
public class Contract_ES : IFuturesContractSelector_ES
{
private readonly Slice _Slice;
private readonly QCAlgorithm _Algorithm_ES;
public Contract_ES(QCAlgorithm Algorithm_ES)
{
_Algorithm_ES = Algorithm_ES;
}
public Contract_ES(Slice slice)
{
_Slice = slice;
}
public void GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach(var chain in slice.FutureChains)
{
if (chain.Value.Symbol.StartsWith("ES"))
{
var ES = (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return ES;
}
}
At the Line return ES, I get this error :
The name "ES" does not exist in the current context.
Weird because I have another method build in this way, with no prob -_-
Maybe using foreach statement that cause the non possible return of "var ES" ?

Passing Nullable Int using reflection

i am using this code
//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Reflection;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
new Program().DoTest();
}
public void DoTest()
{
var a = LoggingAdvice<asd>.Create(new a());
a.targetMethod("nadeem", 123, null);
}
}
public class LoggingAdvice<T> : DispatchProxy
{
private T _decorated;
protected override object Invoke(MethodInfo targetMethod, object[] args)
{
var result = targetMethod.Invoke(_decorated, args);
var resultTask = result as Task;
return result;
}
public static T Create(T decorated)
{
object proxy = Create<T, LoggingAdvice<T>>();
((LoggingAdvice<T>)proxy).SetParameters(decorated);
return (T)proxy;
}
private void SetParameters(T decorated)
{
if (decorated == null)
{
throw new ArgumentNullException(nameof(decorated));
}
_decorated = decorated;
}
}
public class asd
{
public asd()
{
}
public int targetMethod(string name, int number, int? count)
{
Console.WriteLine(name);
Console.WriteLine(number);
Console.WriteLine(count.HasValue ? count.Value.ToString() : "NULL");
return 1;
}
}
}
the most important thing about it, is this line of code
var result = targetMethod.Invoke(_decorated, args);
the target method has 3 parameters, one of them is nullable integer as the following
public int targetMethod(string name, int number, int? count)
the args that is getting passed to Invoke method has the following values as you can view it in the visual studio debugging mode:
["nadeem", 123, (null)]
the invoke is raising an exception that i cannot convert string to nullable integer.
how i can avoid this type of issue, note that i am not sure which function i am going to be invoked, i would only know it on runtime.

Create instances with changing class names

I want to call many tests like this.
var test8001 = new Test8001();
test8001.Execute(drv);
var test8002 = new Test8002();
test8002.Execute(drv);
var test8007 = new Test8007();
test8007.Execute(drv);
How can I automatically instantiate all test function with a int list of all test numbers?
List<int> classNameNumbers = new List<int>() { 8001, 8002, 8007 };
I need a for-loop where Execute() is called on every instance.
Edit:
The name of the type e.g. 'Test8001' should be retrieved from my integer list.
Try out the following
namespace Stackoverflow46529447
{
class Program
{
static void Main(string[] args)
{
var drv = new Drv();
var numbers = new[] {8001, 8002, 8003};
var executables = numbers.Select(x => Activator.CreateInstance(Type.GetType($"Stackoverflow46529447.Test{x:0000}")))
.OfType<IExecutable>()
.ToArray();
foreach (var executable in executables)
{
executable.Execute(drv);
}
}
}
public class Test8001 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8001");
}
}
public class Test8002 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8002");
}
}
public class Test8003 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8003");
}
}
public interface IExecutable
{
void Execute(Drv drv);
}
public class Drv
{
}
}
This uses reflection to create instance types.

Removing and Adding content with Code Fix Provider

I had that previous question which was intended to resolved the state of a local variable / parameter. It works fine, I tweak it a little bit and it looks like this now :
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class LocalVariableNotUsedAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor descriptor = new DiagnosticDescriptor(
CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID,
GettextCatalog.GetString("Local variable is never used"),
GettextCatalog.GetString("Local variable is never used"),
DiagnosticAnalyzerCategories.RedundanciesInDeclarations,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
helpLinkUri: HelpLink.CreateFor(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID)
);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(
(nodeContext) =>
{
Diagnostic diagnostic;
if (TryGetDiagnostic(nodeContext, out diagnostic))
{
nodeContext.ReportDiagnostic(diagnostic);
}
},
SyntaxKind.LocalDeclarationStatement
);
}
private static bool TryGetDiagnostic(SyntaxNodeAnalysisContext nodeContext, out Diagnostic diagnostic)
{
diagnostic = default(Diagnostic);
if (nodeContext.IsFromGeneratedCode())
return false;
var localDeclarationUnused = nodeContext.Node as LocalDeclarationStatementSyntax;
var body = localDeclarationUnused?.Parent as BlockSyntax;
if (body == null)
return false;
var dataFlow = nodeContext.SemanticModel.AnalyzeDataFlow(body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead).ToArray();
if (unused == null)
return false;
if (localDeclarationUnused.Declaration == null || !localDeclarationUnused.Declaration.Variables.Any())
return false;
var localDeclarationSymbol = nodeContext.SemanticModel.GetDeclaredSymbol(localDeclarationUnused.Declaration.Variables.FirstOrDefault());
if (unused.Any())
{
if (unused.Contains(localDeclarationSymbol))
{
diagnostic = Diagnostic.Create(descriptor, localDeclarationUnused.Declaration.GetLocation());
return true;
}
}
return false;
}
}
}
I have build a code fix provider which is working around 40% of the time, when checking the success rate of the NUnit test. Even though I know the code is OK, there seem to be some error on my machine that only arrives when the code fix is being run. I know this because I can debug the analyzer for the tests and each one are fine.
When the code fix provider is being run, I have this error that I can't shake for some reason : "System.ArgumentNullException : Value cannot be null.
Parameter name : declaration"
I have tried debugging the code fix provider, but nothing showed me where that declaration parameter could be located.
Moreover, I am used with code fix providers that need to either replace and remove nodes. But I'm not used to fix an error and add content and I'm wondering how to do such a thing.
Here's my code fix provider which does not take care of adding information at the moment :
using Microsoft.CodeAnalysis;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeFixes;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace RefactoringEssentials.CSharp.Diagnostics
{
[ExportCodeFixProvider(LanguageNames.CSharp), System.Composition.Shared]
public class LocalVariableNotUsedCodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds
{
get
{
return ImmutableArray.Create(CSharpDiagnosticIDs.LocalVariableNotUsedAnalyzerID);
}
}
public override FixAllProvider GetFixAllProvider()
{
return WellKnownFixAllProviders.BatchFixer;
}
public async override Task RegisterCodeFixesAsync(CodeFixContext context)
{
var document = context.Document;
var cancellationToken = context.CancellationToken;
var span = context.Span;
var diagnostics = context.Diagnostics;
var root = await document.GetSyntaxRootAsync(cancellationToken);
var diagnostic = diagnostics.First();
var node = root.FindNode(context.Span);
if (node == null)
return;
var newRoot = root.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia);
context.RegisterCodeFix(CodeActionFactory.Create(node.Span, diagnostic.Severity, "Remove unused local variable", document.WithSyntaxRoot(newRoot)), diagnostic);
}
}
}
and here are the tests that I'm using to make sure that the fix is ok. The last two are running just fine :-)
using NUnit.Framework;
using RefactoringEssentials.CSharp.Diagnostics;
namespace RefactoringEssentials.Tests.CSharp.Diagnostics
{
[TestFixture]
public class LocalVariableNotUsedTests : CSharpDiagnosticTestBase
{
[Test]
public void TestUnusedVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
$int i$;
}
}";
var output = #"
class TestClass {
void TestMethod ()
{
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input, output);
}
[Test]
public void TestUnusedVariable2()
{
var input2 = #"
class TestClass {
void TestMethod ()
{
$int i, j$;
j = 1;
}
}";
var output2 = #"
class TestClass {
void TestMethod ()
{
int j;
j = 1;
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input2, output2);
}
[Test]
public void TestUsedVariable()
{
var input1 = #"
class TestClass {
void TestMethod ()
{
$int i = 0$;
}
}";
var input2 = #"
class TestClass {
void TestMethod ()
{
int i;
i = 0;
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input1);
Analyze<LocalVariableNotUsedAnalyzer>(input2);
}
[Test]
public void TestUnusedForeachVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
var array = new int[10];
foreach (var i in array) {
}
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input);
}
[Test]
public void TestUsedForeachVariable()
{
var input = #"
class TestClass {
void TestMethod ()
{
var array = new int[10];
int j = 0;
foreach (var i in array) {
j += i;
}
}
}";
Analyze<LocalVariableNotUsedAnalyzer>(input);
}
}
}
Is there is anything that is not clear, I will make sure to update my thread appropriately.

how to use loaded DLLS assembly' methods which is referenced to another assembly?

i have 2 assemblies. i added classlib1 into classLib2 references. like that:
and i used it like that:
namespace ClassLibrary2
{
public class Class1
{
public Class1()
{
}
public int GetSum(int a , int b)
{
try
{
ClassLibrary1.Class1 ctx = new ClassLibrary1.Class1();
return ctx.Sum(a, b);
}
catch
{
return -1;
}
}
}
}
Also i want to load (class1lib and Class2Lib) another C# project dynamically by using AppDomain.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Reflection.Emit;
namespace WcfService3
{
public partial class Default : System.Web.UI.Page
{
public static ArrayList arryFiles { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
arryFiles = new ArrayList();
List<byte[]> binaryList = new List<byte[]>();
// string fileName = #"S:\Source\Yusuf.Karatoprak\plugin\ClassLibrary1.dll";
DirSearch(#"S:\Source\Yusuf.Karatoprak\plugin");
foreach (var filePath in arryFiles)
{
FileStream fileStream = File.OpenRead(filePath.ToString());
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, Convert.ToInt32(fileStream.Length));
fileStream.Dispose();
binaryList.Add(buffer);
//Assembly[] assBefore = AppDomain.CurrentDomain.GetAssemblies();
//AppDomain.CurrentDomain.Load(buffer);
//Assembly[] assAfter = AppDomain.CurrentDomain.GetAssemblies();
//Type t = Type.GetType("ClassLibrary1.Class1,ClassLibrary1");
}
new AssemblyLoader().LoadAndCall(binaryList);
}
static void DirSearch(string sDir)
{
try
{
foreach (string f in Directory.GetFiles(sDir, "*.dll"))
{
if (!arryFiles.Contains(f))
arryFiles.Add(f);
}
foreach (string d in Directory.GetDirectories(sDir))
{
if (d != null)
{
foreach (string f in Directory.GetFiles(d, "*.dll"))
{
if (!arryFiles.Contains(f))
arryFiles.Add(f);
}
DirSearch(d);
}
else
break;
}
}
catch (System.Exception excpt)
{
throw new Exception(excpt.Message);
}
}
}
public class AssemblyLoader : MarshalByRefObject
{
public void LoadAndCall(List<byte[]> binaryList)
{
Assembly loadedAssembly=null;
Assembly[] assBefore = AppDomain.CurrentDomain.GetAssemblies();
foreach (byte[] binary in binaryList)
{
loadedAssembly = AppDomain.CurrentDomain.Load(binary);
}
Assembly[] assAfter = AppDomain.CurrentDomain.GetAssemblies();
object[] tt = { 3, 6 };
Type type = loadedAssembly.GetType("ClassLibrary2.Class1");
object loaded = loadedAssembly.CreateInstance("ClassLibrary2.Class1", true, BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance, null, new object[] { }, null, null);
// object obj = Activator.CreateInstance(type);
ObjectCreateMethod inv = new ObjectCreateMethod(type); //Specify Type
Object obj = inv.CreateInstance();
MethodInfo minfo = type.GetMethod("GetSum", BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance);
int x = (int)minfo.Invoke(obj, new Object[] { 3, 6 });
Console.WriteLine(x);
}
}
public class ObjectCreateMethod
{
delegate object MethodInvoker();
MethodInvoker methodHandler = null;
public ObjectCreateMethod(Type type)
{
CreateMethod(type.GetConstructor(Type.EmptyTypes));
}
public ObjectCreateMethod(ConstructorInfo target)
{
CreateMethod(target);
}
void CreateMethod(ConstructorInfo target)
{
DynamicMethod dynamic = new DynamicMethod(string.Empty,
typeof(object),
new Type[0],
target.DeclaringType);
ILGenerator il = dynamic.GetILGenerator();
il.DeclareLocal(target.DeclaringType);
il.Emit(OpCodes.Newobj, target);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
}
public object CreateInstance()
{
return methodHandler();
}
}
}
Why can not load and Exception error return to me:
Look inner exception: Could not load file or assembly 'ClassLibrary1 But i loaded Classlib2 abd Classlib1 . class2 depends on classlib1 how to use classlib1 method i want to use GetSum(int a , int b) method after load assemblies:
Found this somewhat similar question. Handling the resolve event seems to be a last ditch effort. Just try it if you run out of options. Replace with your S:\Source\Yusuf.Karatoprak\plugin. You can also try handling the AppDomain.AssemblyLoad event, to see what was loaded from your binaries.
#programmerist, cheers!
Not very sure if it's possible to link a reference to another DLL to the assembly duriong dynamic load. Not at least that I'm aware of. But generaly,
if you're talking about plugins, do not link them together. If not, there is no any reason to have plugin based system.
I would try to check the .NET Framework version of your host app, in regard of the plugins it loads. Could be some versioning conflict.
Hope this helps.

Categories

Resources