Can you reference a non-static method in a static context? - c#

Use of delegates follows the same rules as calling methods - you can only refer to a method via a delegate if you are allowed to call that method explicitly, which means you cannot reference a non-static method from a static method, even if you don't actually call it. Is there a way around that?
Here is some code used in performing the Bowling Kata, with my ideal lines of code shown in comments. I was forced to go through a static call (and anonymous static method declarations) to make the Frame Class code declarative to my liking:
public int FrameScore()
{
return scorer[FrameType()](this);
// I would like it to be
// return this.scorer[FrameType()]();
}
static Dictionary<LinkedFrame.FrameTypeEnum, Func<LinkedFrame, int>> scorer =
new Dictionary<LinkedFrame.FrameTypeEnum, Func<LinkedFrame, int>>()
{
{LinkedFrame.FrameTypeEnum.Strike, frame => frame.StrikeScore()},
{LinkedFrame.FrameTypeEnum.Spare, frame => frame.SpareScore()},
{LinkedFrame.FrameTypeEnum.Regular, frame => frame.RegularScore()}
// I would like an element to be
// {LinkedFrame.FrameTypeEnum.Strike, StrikeScore}
};
private int RegularScore()
{
return this.Sum;
}
private int SpareScore()
{
...
}
private int StrikeScore()
{
...
}
So in some contexts it would make sense to reason about non-static methods in a static context. Is there a way to do this?

Maybe open instance delegates will help?
According to MSDN: Delegate Class:
When a delegate represents an instance method closed over its first argument (the most common case), the delegate stores a reference to the method's entry point and a reference to an object, called the target, which is of a type assignable to the type that defined the method. When a delegate represents an open instance method, it stores a reference to the method's entry point. The delegate signature must include the hidden this parameter in its formal parameter list; in this case, the delegate does not have a reference to a target object, and a target object must be supplied when the delegate is invoked.
What it comes down to, is that you can sneakily convert an instance method to a static method with an explicit this parameter. You can see how it's done here: Simon Cooper: Introduction to open instance delegates

An instance method always requires an instance to be invoked with.
If you want to invoke an instance method through a delegate, you have two options:
The delegate captures the instance in some way.
You need to pass the instance to the delegate.
You seem to want to have a delegate that does not capture an instance and does not require an instance to be passed. That's not possible in C#.

Related

How does func ACTUALLY work

So when I return an object, under the covers I think it's returning the memory address to that object (or an object containing the memory address) which you can reference and use.
But what is actually happening when you return a func?
How does your app know which instance of an object to use with that func?
My instinct tells me that an object instance reference is passed along with the func but is that what is actually happening?
I can't seem to find much on this topic.
Edit:
To clarify, I am asking when a method returns a func
A Func is a delegate -- a type of object that is associated with a specific method signature and is usually bound to a specific method with that signature. This might be either a static or an instance method and it might be generic or not; in all cases, the delegate instance holds all the information required to call the method.
A Func is a delegate, and Delegate instances encapsulate a MethodInfo and an optional target object to invoke the method on when invoked.
Func<T> is just a delegate. If it is set to an instance method, then, it [magically] gets the correct this value when invoked. If set to a static method, then there is no this. And if it's set to a closure/lambda, the closure "captures" those variables in scope at the time of closure. lexical scope (with some caveats: things don't always work the way you think they might).
Edited to add:
From the C# standard, ISO 23270:2006 Information Technology — Programming Languages — C#, §8.10:
8.10 Delegates
Delegates enable scenarios that some other languages have addressed with function
pointers. However, unlike function pointers, delegates are object-oriented and type-safe.
A delegate declaration defines a class that is derived from the class System.Delegate.
A delegate instance encapsulates one or more methods, each of which is referred to as
a callable entity. For instance methods, a callable entity consists of an instance
and a method on that instance. For static methods, a callable entity consists of just
a method. Given a delegate instance and an appropriate set of arguments, one can invoke
all of that delegate instance’s methods with that set of arguments.
In more detail, the other standard, ISO 23271:2006 Information Technology — Common Language Infrastructure (CLI) Partitions I to VI says in §14.6:
The instance constructor (named .ctor and marked specialname and rtspecialname,
see §10.5.1) shall take exactly two parameters, the first having type System.Object,
and the second having type System.IntPtr. When actually called (via a newobj
instruction, see Partition III), the first argument shall be an instance of the class
(or one of its derived classes) that defines the target method, and the second argument
shall be a method pointer to the method to be called.
It's not that magic.
When you create an anonymous method, such as one assigned to a Func<T>, locals used inside of it are lifted into a class. Consider this:
int GetIncremented()
{
int x = 0;
Func<int> increment = () => ++x;
increment();
return x;
}
Behind the scenes, something like this will be created:
sealed class FuncData
{
public int x = 0;
public int FuncIncrement(FuncData data)
{
return ++data.x;
}
}
int GetIncremented()
{
FuncData data = new FuncData();
Func<int> increment = new Func<int>(data.FuncIncrement);
increment();
return data.x;
}
This is why out and ref parameters can't be used with anonymous methods: you can't store an out or ref as a member variable in a class.
You have both Func and Action, which are in-built delegates. The difference between these is that Func returns a type and Action does not.
You'll find Func uses heavily in the IEnumerable(T) Interface, with Linq extension methods.
Take a look at this example from the MSDN link provided...
Func<string, string> selector = str => str.ToUpper();
string[] words = { "orange", "apple", "Article", "elephant" };
IEnumerable<String> aWords = words.Select(selector);
foreach (String word in aWords)
Console.WriteLine(word);
This essentially uses the Selector Func to convert each of the strings in words to upper case.

Passing null value to overloading method where Object and String as param in C#

I have two overloaded methods like below
public class TestClass
{
public void LoadTest(object param)
{
Console.WriteLine("Loading object...");
}
public void LoadTest(string param)
{
Console.WriteLine("Loading string...");
}
}
After calling this method like below it will show the output as Loading string... Please explain how .net handle this scenario?
class Program
{
static void Main(string[] args)
{
var obj=new TestClass();
obj.LoadTest(null);
// obj.LoadType(null);
Console.ReadLine();
}
}
The C# compiler takes the most specific overload possible.
As string is an object, and it can have the value of null, the compiler deems string to be more specific.
null is a valid string.
It will try to match the most specific type and string is more specific than object
Depending on your use you should probably remove the parameter totally in the object overload.
This is just the way C# compiler prioritizes to determine which method is better to call. There is one rule:
If method A has more specific parameter types than method B, then method A is better than method B in overload case.
In your case, apparently string is more specified than object, that is why LoadTest(string param) is called.
You can refer 7.5.3.2 Better function member in C# language specification to get more understanding.
because compiler takes the closest possible specific method that can be accessed (null to string is closer than null to object) that is available. And in this case as both as overload with string is closer, that is why it is called.
This is what MSDN has to say
Once the candidate function members and the argument list have been identified, the selection of the best function member is the same in
all cases:
Given the set of applicable candidate function members, the best function member in that set is located.
If the set contains only one function member, then that function member is the best function member.
Otherwise, the best function member is the one function member that is better than all other function members with respect to the given
argument list, provided that each function member is compared to all
other function members using the rules in Section 7.4.2.2.
If there is not exactly one function member that is better than all other function members, then the function member invocation is
ambiguous and a compile-time error occurs.

What is this delegate method doing?

I've been reading the MSDN page on delegates and they seem straightforward. Then I was looking at some code that uses them and I saw this:
public delegate void NoArguments();
public NoArguments Refresh = null;
Refresh = new NoArguments( Reset );
It's that third line that confuses me. How can you new a delegate? It is not an object, it's a method, or rather a delegate to a method. According to the example on the MSDN page, creating an instance of a delegate is through simple assignment, not allocaiton. Furthermore, why is the new for the delegate taking a parameter, Reset, when the delegate declaration takes no parameters?
The delegate keyword indicates that what follows is essentially a function signature, so therefore, Refresh becomes kind of like a pointer to a function that takes no arguments. However, to assign something to the Refresh pointer, you have to give it a function to point to. In this case, it's the Reset function. And further, the Reset function must take no arguments.
In addition, the syntax:
Refresh = Reset;
is also valid, and is just syntactic sugar for the more formal syntax:
Refresh = new NoArguments(Reset);
in both cases, you could then execute the Reset function by calling Refresh:
Refresh();
Note, however, that if you execute Refresh() without it having been assigned, then you could generate an exception. The way to prevent this would be to check it against null:
if (Refresh != null) Refresh();
else {
// Refresh was never assigned
}
You may think delegate is like a function type:
Declare type, function returns void and have no arguments:
public delegate void NoArguments();
Declare variable of given type and initialize it:
public NoArguments Refresh = null;
Assign new object to your variable. Object is actually a function Reset, which must have the same signature as your delegate:
Refresh = new NoArguments( Reset );
UPDATE:
You may review the following link for more details: C# Delegates
Delegate is "delegate to a method", but also an object. If you look at NoArguments in any decompiler, you will see it is actually a class inheriting from MulticastDelegate, with several methods (Invoke, BeginInvoke, EndInvoke).
For historical reasons, C# allows you to create instances of that class using new NoArguments(method). However in modern versions it also supports a shortcut notation method that does the same thing. In both cases, you actually do have an object of type NoArguments in Refresh.

C# reflection - get entire parameter list for method (including the parameter for "this")

I'm making a silly AOT .net compiler for fun, and ran into a problem.
I'm just loading the assembly into memory (I'm writing it in C#) and spamming reflection left and right to get the information I need (such as the CIL for the method bodies).
This page says "We need the reference to the current instance (stored in local argument index 0) [...]". However, when I call MethodInfo.GetParameters(), this argument is not returned.
I'm resolving the fields in opcodes such as Ldarg to ParameterInfo objects, and not raw indices, so it gets very confused when "Ldarg.0" is inside an instance method - since arg 0 is not in GetParameters!
My main question: Is there some way I can get an instance of the ParameterInfo object for the this object (parameter index 0), or do I have to just use raw indices? (I really don't want to use int indices...)
Here's some code, since code is nice. (contained inside the class Program)
static void Main(string[] args)
{
// obviously throws an IndexOutOfRangeException instead of returning the (true) argument 0
Console.WriteLine(typeof (Program).GetMethod("Test").GetParameters()[0]);
}
public void Test()
{
}
You don't get a ParameterInfo for that. Simply: if it is an instance method, there is a "this" that maps to the arg-0 of the method's declaring type. It has no name and no interesting properties other than its type. All other parameters are offset by one. For static methods this is not the case. Note that this gets even more interesting for instance methods on value-types where it is a by-ref argument.

Are method names implicitly cast to delegate types?

Im having a little trouble understanding delegates.
I have a delegate that i will invoke when a y character is entered:
public delegate void respondToY(string msgToSend);
private respondToY yHandler;
i have a subscribe method in order that calling code can ask to be notified when the delegate is invoked:
public void Subscribe(respondToY methodName)
{
yHandler += methodName;
}
As far as i can see, to register with this delegate, i need to provide something of the type respondToY. Yet when calling the subscribe method, i can supply either a new instance of the delegate or simply the name of the method. Does this mean that any method matching the delegate signature can be used and will automatically be converted to the correct delegate type?
** Edit **
So on this assumption it would also be valid to supply only a method name to things like click event handlers for buttons (provided the method took the sender, and the relevant event object), it would be converted to the required delegate?
This is a method group conversion. It converts a method group (basically the name of a method or overloaded methods) to an instance of a delegate type with a compatible signature.
Yes, any compatible method can be used. Note that you can provide a target too - for example:
string text = "Hello there";
Func<int, int, string> func = text.Substring;
Console.WriteLine(func(2, 3)); // Prints "llo", which is text.Substring(2, 3)
There must be a specific delegate type involve though. You can't just use:
Delegate x = methodName;
... the compiler doesn't know the kind of delegate to create.
For more information, see section 6.6 of the C# 4 language specification.
Note that a method group conversion always creates a new instance of the delegate in question - it isn't cached (and can't be without violating the specification.)
as far as i know ... yes, the delegate type just makes sure that the signatures match

Categories

Resources