I need to know if it's possible to access the underlying object that contains the method referenced by a delegate?
I know that the object is captured in the delegate because it is required when invoking the method.
A Delegate references it's target. Of course, static methods have no target, so a null check might be required.
class Program
{
static void Main(string[] args)
{
var container = new Container();
Func<string> doSomething = container.DoSomething;
Delegate d = doSomething;
// This will be the container, but you need to cast.
var c = (Container)d.Target;
Console.Read();
}
}
class Container
{
public string DoSomething()
{
return "";
}
}
I'm not sure what you are trying to achieve with this, but needing to know about the target type that is fulfilling a delegate reference might be a code smell or an indicator of a design issue.
Related
After loading a DLL and obtaining a type, I get an exception trying to instantiate it:
Assembly dll = Assembly.LoadFrom(#"C:\path\file.dll");
Type type = dll.GetType("namespace.CustomClass");
object obj = Activator.CreateInstance(type); // <-- System.MissingMethodException
"No constructor with 0 parameters defined for this object" (average translation)
Exploring the loaded type, I can see the DeclaredConstrunctors -> {Void .ctor()}
But calling type.GetConstructors() I get an empty array (I guess that means that only default constructor exists?)
I neither found any factory class that returns an object of my class, or an getInstance function.
Any idea how to proceed?
There are a few possibilities here.
The first is that the all of the defined parameters take parameters. There's no guarantee that every class has a 0-parameter constructor. Here's an example of some code that produces this error:
public class SomeCons
{
public SomeCons(string cons)
{
}
}
static void Main(string[] args)
{
object result = Activator.CreateInstance(typeof(SomeCons));
}
The second possibility namespace.CustomClass has a private constructor. The following code produces similar behavior to what you saw. I also included an example of how to find the actual constructor - you want to use Binding Flags.
private class NoCons
{
private NoCons()
{
}
}
static void Main(string[] args)
{
// As you saw, this shows one declared constructor
Type exploratory = typeof(NoCons);
// Returns nothing
ConstructorInfo[] constructors = typeof(NoCons).GetConstructors();
// Returns 1 constructor
constructors = typeof(NoCons).GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
Please note that it may be important to understand exactly why namespace.CustomClass has a private constructor in the first place. That's actually a really common thing to do if you're trying to define a Singleton, in which case you probably don't want to call the constructor directly.
For a singleton like this:
private class NoCons
{
private NoCons()
{
}
private static NoCons _instance;
public static NoCons Instance
{
get
{
if (_instance == null)
{
_instance = new NoCons();
}
return _instance;
}
}
}
try something like this:
Type exploratory = typeof(NoCons);
PropertyInfo singletonProperty = exploratory.GetProperties(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(prop => prop.Name.Contains("Instance"));
string name = singletonProperty.GetGetMethod().Name;
var noCons = exploratory.GetMethod(name).Invoke(null, null) as NoCons;
The DLL had a related OCX file placed in another folder.
The file has been registered using:
Regsvr32 .\file.ocx
After that, I've been able to instantiate an object calling:
using Microsoft.VisualBasic;
MyAssemblyName object = (MyAssemblyName) Interaction.CreateObject( "MyNamespace.MyAssemblyName", "");
Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?
Further, why is it that I have to new up a MyClass to use MyVoidAction?
See code below:
using System;
public class MyClass
{
public delegate void MyDeler();
public Action MyVoidAction;
}
class MainClass
{
static void Main()
{
MyClass.MyDeler d = () => Console.WriteLine("my deler");
d();
// MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
MyClass meClass = new MyClass();
meClass.MyVoidAction = () => Console.WriteLine("my void action");
meClass.MyVoidAction();
}
}
I looked up this answer: Accessibility between Action and Delegate
That cleared up a lot, but I'm not sure I'm 100% on this. So according to that answer, the delegate void MyDeler() defines a type, which confuses me because I imagine something like this:
using System;
class MainClass
{
class MyClass
{
public static class DelegateClass
{
public void DoDel() // isn't even legal?
{
Console.WriteLine("DoDel()");
}
}
}
static void Main()
{
//MyClass.DelegateClass d = new asdf // ??? something like this?
}
}
Help appreciated!
Let's demystify this:
When you declare MyDeler:
public delegate void MyDeler();
What you are doing is defining a type of method to which execution will be "delegated". In other words, you are saying there is method out there that follows this signature and I intend to keep references to it. In order for the compiler to identify these references, this type will be used.
It follows then that you will need to actually have a real pointer to the method, since this is just your "definition". That's why you will need a variable of type "MyDeler" to which you can assign the actual method to call:
MyClass.MyDeler d = () => Console.WriteLine("my deler");
This line is saying "create a variable named d of type MyClass.MyDeler that holds a reference to this inline method". From here on, when you call d(); the pointer will actually execute the inline method.
For the action:
public Action MyVoidAction;
You are now declaring a public property of the class. Therefore, you need an instance of the class before you can use this property.
The trick here is that Action is a known definition of a delegate. Microsoft has a built-in type that you can use instead of declaring your own void MyDeler();. It's essentially syntactical sugar but remember, it's still a type and as you have created a public property, you now need to assign it the method that will actually execute and as we discussed before, you need an instance:
MyClass meClass = new MyClass(); //Instance creation
meClass.MyVoidAction = () => Console.WriteLine("my void action"); //Tell your delegate what to delegate to.
meClass.MyVoidAction(); //Run the inline method!
I hope that helps.
MyDeler is a type declaration, not a variable declaration. You can't store things in it or assign to it.
To create a field for storing a MyDeler instance, add this line to MyClass:
public MyDeler MyDelerField;
Now you can assign to it.
Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?
The declaration of MyDeler declares a type within MyClass. It's similar to declaring any other nested type, like:
class MyClass
{
public class MyNestedClass { }
}
It is a member of the type MyClass, not of any actual instance of MyClass, nor even of the class MyClass as a static member would be.
A nested type is neither "instance" nor "static", because it's part of the type system, not part of the class itself.
why is it that I have to new up a MyClass to use MyVoidAction?
Because MyVoidAction is a member of the class, and is an instance member. So you are required to have an instance of the class to access it.
the delegate void MyDeler() defines a type, which confuses me because I imagine something like this
Your declaration in that example of public static class DelegateClass is doing something completely different. An unfortunate aspect of C# is the use of static to refer to a variety of different things. It's not quite as bad as in Java, but it can still be confusing (as you're finding out).
In that declaration, the use of the word static does not make DelegateClass a "static member" of the containing type MyClass. Instead, the word static as part of a class declaration means that the entire class will contain only static members.
Thus, when you declare DoDel() without the static keyword, you are attempting to declare an instance member, i.e. that method, in a class where you've promised to declare only static members. If you add static to the method declaration, it would compile.
Not that doing so would make the DelegateClass class in that example similar to the MyVoidAction member in your other example. It's still a type declaration, declaring a nested type within the MyClass class, and would still follow the rules for types, not class members. But I hope that at least explains to you why the example that's confusing you works the way it does.
Action and a delegate of a method with no parameters and that returns void are formally the same thing.
If u take a look to: https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx you can see that:
You can use this delegate to pass a method as a parameter without
explicitly declaring a custom delegate.
I hope this example helps:
public delegate void DelegateMyDeler(); //This is a custom delegate
public class MyClass
{
public DelegateMyDeler MyDeler; //This use your custom delegate
public Action MyVoidAction; // This use Action delegate
}
class MainClass
{
static void Main()
{
// MyClass.MyDeler d = () => Console.WriteLine("my deler"); // Now this is not allowed too!
// d();
// MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
MyClass meClass = new MyClass();
meClass.MyDeler = () => Console.WriteLine("my deler");
meClass.MyDeler();
meClass.MyVoidAction = () => Console.WriteLine("my void action");
meClass.MyVoidAction();
//but you can do (you custom delegate is defined out of the class in this case
//so you have not to add the class prefix):
DelegateMyDeler d = () => Console.WriteLine("my deler 2");
d();
// or
DelegateMyDeler d3 = () => Console.WriteLine("my deler 3");
d3.Invoke();
// and in a real case, for example:
DelegateMyDeler undeterminedMethod;
int x = 3;
switch (x)
{
case 1:
undeterminedMethod = deler1;
break;
case 2:
undeterminedMethod = deler2;
break;
case 3:
undeterminedMethod = deler3;
break;
default:
undeterminedMethod = null;
break;
}
undeterminedMethod?.Invoke(); //In case x is minor than 1 or major than 3, nothing happens
}
static void deler1() { Console.WriteLine("my deler 1"); }
static void deler2() { Console.WriteLine("my deler 2"); }
static void deler3() { Console.WriteLine("my deler 3"); }
}
I have referenced one DLL (I have source code of this) say Dll_A in which there is a function
private void uploadPic(int a)
In my main project, I have a function say
private void passMe(int b)
{
}
I need to pass the above function (passMe) to uploadPic function in Dll_A, how can I do that? Is it possible?
I am able to use functions of the Dll_A from my main project, so instantiating isn't a problem, I just need a way to pass function.
===
Thanks, giving it a try. If some can edit code below
//code in main project picbackman.cs
public delegate void delObj(int v);
private void uploadSome(string path, string fName, string str)
{
delObj del1 = new delObj(updatePValue);
UploadFileResponse response = boxProvider1.UploadFiles(args1, folderString, ((Picbackman.BoxProvider.delObj)( del1)));
}
//code in different dll which is referenced in main project //Dll_A
public delegate void delObj(int v);
public UploadFileResponse UploadFiles(string[] filePathes,string folderId, delObj d)
{}
First of all your method will need to accept a delegate as one of it's parameters. That would be something like
private void uploadPic(Action<int> func,int a){
//at some point do func(someInt);
}
at another point declare anothe method or function
public class someClasse {
public vois passMe(int b){
...
}
}
First of all notice that the access modifier has changed. if they are not in the same class you will need to be able to access one from the other so they can't both be private and since they are in different assemblies internal won't work either.
when you need the delegate do like this
var obj = new someClass();
var myInt = 5; //or whatever the value is
uploadPic(obj.passMe,myInt);
notice that the method is used with out arguments. When using a method without arguments the compiler will try and convert it to a suitable delegate.
I'd recommend you not to use delegate but stick with Func/Action they are delegates but more generic
public delegate void DelObj1();
public delegate void DelObj2()
public void F(){};
var del1 = new DelObj1(F);
var del2 = new DelObj2(F);
you can't pass a del1 where a DelObj2 is needed even though you use the same method for each. You will not have that issue if you use Action/Function
Action del1 = F;
Action del2 = F;
The reason is that DelObj1 and DelObj2 are two distinct classes with the same base class Ie they are siblings in the type tree. Using Action the type is the same for both del1 and del2
You should have a look at Delegates.
From the documentation:
A delegate is a type that references a method. Once a delegate is
assigned a method, it behaves exactly like that method. The delegate
method can be used like any other method, with parameters and a return
value
and
Delegates allow methods to be passed as parameters
So in your case you should be able to do something like this:
// define the delegate
public delegate int PictureDelegate(int value)
// define your passMe function (in the class MyClass for example)
public int passMe(int value)
{
return value + 1;
}
// when you want to use it
MyClass myInstance = new MyClass();
PictureDelegate passFunc = new PictureDelegate(myInstance.passMe);
myDll.uploadPic(passFunc, 12);
This question already has answers here:
Calling a function from a string in C#
(5 answers)
Closed 1 year ago.
I have a struct-array that contains details of different reports that can be run. Each report calls a different method and currently the program has to manually check the selected report value to specifically call the appropriate method.
I would like to store the method name in the struct-array and then have program invoke that method when there is match. Is this possible?
Currently:
if (this.cboSelectReport.Text == "Daily_Unload")
{
reportDailyUnload();
}
Ideally:
if(this.cboSelectReport.Text == MyArray[i].Name)
{
something(MyArray[i].MethodName);
}
UPDATE
I tired a number of the suggestions below and none of them worked. They didn't work probably due to how I have my program structured.
You can do it using reflection, but IMO it is too fragile: it introduces an invisible dependency on the name of the method that you call.
// Assuming that the method is static, you can access it like this:
var namedReportMethod = "MyReport1";
var reportMethod = typeof(ReporterClass).GetMethod(namedReportMethod);
var res = reportMethod.Invoke(null, new object[] {reportArg1, reportArg2});
A better approach would be to define a delegate based on your method, and store it in the struct/class instead of the method name.
delegate void ReportDelegate(int param1, string param2);
class Runner {
public static void RunReport(ReportDelegate rd) {
rd(1, "hello");
}
}
class Test {
static void TestReport(int a, string b) {
// ....
}
public static void Main(string[] args) {
Runner.RunReport(TestReport);
}
}
Instead of defining your own delegate types, you can use pre-defined ones based on Action<T1,T2,...> or Func<T1,T2,R>, depending on your need to return values from the reports.
Rather than storing the method name, you could store a delegate:
struct ReportInfo
{
public string Name { get; set; }
public Action Method { get; set; }
}
//...
MyArray[0] = new ReportInfo { Name = "Daily_Unload", Action = this.reportDailyUnload };
//...
if(this.cboSelectReport.Text == MyArray[i].Name)
{
MyArray[i].Method.Invoke();
}
Most people seem to prefer the alternative syntax where you can invoke a delegate as if it were a method, using a list of arguments in parentheses. I tend to avoid this, because it can be ambiguous whether the thing being invoked is a method or a delegate:
MyArray[i].Method();
In this case, we're invoking the delegate that is referred to by the Method property, but this code could also represent a call to a method called "Method". Confusing.
As for me, supporting simple switch is much easier than dealing with reflection, array of method names or delegates, and invoking that stuff:
switch (reportType)
{
case "Daily_Unload":
ReportDailyUnload();
break;
// ...
}
If all the methods share the same signature, one way would be to cache a delegate:
// initialize, maybe in a constructor
Dictionary<string, Action> nameDelegateMapping = new Dictionary<string, Action>();
// setup the delegates
nameDelegateMapping.Add("Daily_Unload", reportDailyUnload);
// ... add more methods here.
// later
string methodName = this.cboSelectReport.Text;
Action action;
if (nameDelegateMapping.TryGetValue(methodName, out action))
{
action();
}
else
{
// tell user the method does not exist.
}
Yes, what you are talking about is reflection. Here is an article on how to invoke a method. There is a lot you can find on reflection using google.
Add a delegate property to your struct (e.g. of type Action) then just invoke this delegate when you need it. Just set this property to the method you want to call when instantiating the struct instances.
Using a delegate and dictionary<string, delegate>
void Main()
{
var reports = new Dictionary<string, Report>
{
{"Daily_Unload", ReportDailyUnLoad}
};
var report = "Daily_Unload";
reports[report]();
}
delegate string Report();
string ReportDailyUnLoad()
{
return "daily unload report";
}
Say I have 2 classes, class A and class B. Class A creates an instance of Class B. Class A has a function that I would like to pass into a method from Class B.
class A {
void Main(string[] args) {
B classB=new B();
DelegateCaller(new delFunction(classB.TheFunction()); // <-- Won't compile (method name expected)
DelegateCaller(new delFunction(B.TheFunction()); // <-- Won't compile (object reference is req'd)
}
public delegate string delFunction();
public DelegateCaller(delFunction func) {
System.Console.WriteLine(func());
}
}
class B {
public string TheFunction() {
return "I'm Printing!!!";
}
}
I'm not sure if it a syntax issue or it's just something I can't do. Maybe I need to define the delegate in B, but reference it in A? What about B's this pointer?
It's just a syntax issue; get rid of the parentheses after classB.TheFunction - they indicate that you wish to invoke the method.
DelegateCaller(new delFunction(classB.TheFunction));
Do note that there is an implicit conversion available from a method-group, so you can just do:
DelegateCaller(classB.TheFunction);
Also note that creating your own delegate-type in this case is unnecessary; you could just use the in-built Func<string> type.
EDIT: As Darin Dimitrov points out, there is also the unrelated issue of calling an instance method as though it were a static method.
Try like this:
class A
{
static void Main()
{
B classB = new B();
DelegateCaller(classB.TheFunction);
}
public delegate string delFunction();
public static void DelegateCaller(delFunction func)
{
Console.WriteLine(func());
}
}
class B
{
public string TheFunction()
{
return "I'm Printing!!!";
}
}
Let me elaborate about the different changes I've made to your initial code:
TheFunction in class B needs to be public so that you can access it from class A
The DelegateCaller method in class A should be static and not necessarily return a value (declare it as void) if you want to call it from the static Main method.
The definition of the delFunction delegate should return a string.
Take the parenthesis off the end of TheFunction. You want the method, not the result of a call to the method.
If you want to capture an instance method for usage in a general purpose fashion you should use Delegate.CreateDelegate(Type,MethodInfo). This is nice as it allows you to create an "open delegate" meaning it isn't bound to an instance and can take any instance that is a ClassB. It makes reflection quite fast if you know the type information, as this method will perform much faster than the equivalent statement using MethodInfo.Invoke.
DelegateCaller(new delFunction(B.TheFunction());
Should be
DelegateCaller(new delFunction(B.TheFunction);
To use classB.TheFunction you would need to make TheFunction static. You pass in the function with no parens.