How to call non static methods from Action<T> delegate in C# - c#

Since I am writing a generic concept for some action to be perform, I need to call some non static method in the Action delegate. Also, none of them are static in my code. But still I can't call the non static method inside the Action definition.
Here's my code-
private Dictionary<string, Action<object>> m_dicUndoRedoAction = new Dictionary<string, Action<object>>();
m_dicUndoRedoAction.Add("DeleteClass", DeleteClassFromeNode );
and Here's the definition of DeleteClass
private Action<object> DeleteClassFromeNode =
data =>
{
Tuple<itemType1, itemType2> items = data as Tuple<itemType1, itemType2>;
if (items != null && items.Item2 != null)
{
DeleteClass(items.Item2); // This is my non static method in the same class.
}
};
and Here's how I call the delegate
private void Undo_Executed(object sender, ExecutedRoutedEventArgs e)
{
object temp;
if (UndoRedoAction.DoUndo(out temp))
{
m_dicUndoRedoAction["DeleteClass"].Invoke(temp);
}
}
as compiler says
A field initializer cannot reference the non-static field, method, or
property 'DeleteClassFromeNode'
I have also reviewed MSDN reference for Action article, but nowhere MS has mentioned whether, Action is implicitly static, or am I going some wrong way ?
I also looked up on some nonstatic call from static methods, but none of them were satisfactory explained.
I would appreciate it if anyone provide its low level explanation.
On response to Peter explanation
Though initializers run before the constructor has completed, that doesn't make it to trigger the delegate in between the constructor execution. Even if you will look up its assembly code in ILDASM, it shows the real action Field as non static, but cached anonymous delegate object as static. Why this different behavior by compiler ?

Just as the compiler is telling you, you are prohibited from using non-static members in an initializer. This is because initializers run before the constructor has completed, and so it is not necessarily safe to use non-static members.
Instead, just perform the initialization in the constructor:
public MyClass()
{
DeleteClassFromeNode = data =>
{
Tuple<itemType1, itemType2> items = data as Tuple<itemType1, itemType2>;
if (items != null && items.Item2 != null)
{
DeleteClass(items.Item2); // This is my non static method in the same class.
}
};
// Other initialization code can go here (or before...whatever is most appropriate)
}

Related

Provide extension method for types derived from `this` type

I've read this similar question I don't expect the same behavior as the OP and I don't really understand him but I have a usage for protected members inside the derived classes.
In Why is the 'this' keyword required to call an extension method from within the extended class Eric Lippert wrote:
... If you are in the scenario where you are using an extension method
for a type within that type then you do have access to the source
code. Why are you using an extension method in the first place then?
... Given those two points, the burden no longer falls on the language
designer to explain why the feature does not exist. It now falls on
you to explain why it should. Features have enormous costs associated
with them.
...
So I will try to explain why I would expect a behavior and it's usage example.
The feature:
A programer can access protected member of this object inside extension method.
When a protected member is used within extension method, you can only use the method inside classes derived from type of this object.
Protected extension method can be called only with this argument object which is the same object that is accessible by this keyword in caller method.
Real life usage scenario:
I'm playing with creating a Visual Studio custom editor based on WPFDesigner_XML example.
Currently I'm trying to figure things out in class with following signature:
public sealed class EditorPane : WindowPane, IOleComponent, IVsDeferredDocView, IVsLinkedUndoClient
{...}
Lot of methods are using services Like this:
void RegisterIndependentView(bool subscribe)
{
IVsTextManager textManager = (IVsTextManager)GetService(typeof(SVsTextManager));
if (textManager != null)
{
if (subscribe)
{
textManager.RegisterIndependentView(this, _textBuffer);
}
else
{
textManager.UnregisterIndependentView(this, _textBuffer);
}
}
}
I like to keep focus on things that actually matter so I wrote helper method to simplify such methods. For example:
private void RegisterIndependentView(bool subscribe) {
if (with(out IVsTextManager tm)) return;
if (subscribe) tm.RegisterIndependentView(this, _textBuffer);
else tm.UnregisterIndependentView(this, _textBuffer);
}
The with method look like this:
private bool with<T>(out T si) {
si = (T)GetService(getServiceQueryType<T>());
return si == null ? true : false;
}
And I placed getServiceQueryType<T>() in a static class:
public static class VSServiceQueryHelper {
public static Type getServiceQueryType<T>() {
var t = typeof(T);
if (!serviceQueryTypesMap.ContainsKey(t)) throw new Exception($#"No query type was mapped in ""{nameof(serviceQueryTypesMap)}"" for the ""{t.FullName}"" interface.");
return serviceQueryTypesMap[t];
}
private static Dictionary<Type, Type> serviceQueryTypesMap = new Dictionary<Type, Type>() {
{ typeof(IVsUIShellOpenDocument), typeof(SVsUIShellOpenDocument) },
{ typeof(IVsWindowFrame), typeof(SVsWindowFrame) },
{ typeof(IVsResourceManager), typeof(SVsResourceManager) },
{ typeof(IVsRunningDocumentTable), typeof(SVsRunningDocumentTable) },
{ typeof(IMenuCommandService), typeof(IMenuCommandService) },
{ typeof(IVsTextManager), typeof(SVsTextManager) },
};
}
This works well but I would also like to place the with method inside VSServiceQueryHelper as an extension so any time I would extend WindowsPane i could just place using static com.audionysos.vsix.utils.VSServiceQueryHelper; at the top and use the with method that is already implemented.
The problem:
I can't make with method an extension because the GetService method used by it is a protected member of the WindowsPane which is the base type of my class. So now I need to place with implementation in every class that extends WindowPane and this breaks the rule of never repeat yourself :/
A simple solution would be to create a base class containing the With method.
If that is too burdensome, then you can also implement this using Reflection to invoke the GetService method from the extension method. In fact, we can create a delegate to it that will ensure there is minimal overhead to invoking With many times.
internal static class WindowPaneExtensions
{
private static readonly Func<WindowPane, Type, object> WindowPaneGetService = CreateWindowPaneGetService();
public static bool With<T>(this WindowPane pane, out T service)
{
service = (T)WindowPaneGetService(pane, GetServiceQueryType<T>());
return service != null;
}
private static Func<WindowPane, Type, object> CreateWindowPaneGetService()
{
var method = typeof(WindowPane).GetMethod("GetService", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(Type) }, null);
var del = (Func<WindowPane, Type, object>)method.CreateDelegate(typeof(Func<WindowPane, Type, object>));
return del;
}
}
I think your proposal to allow certain extension methods access to protected members is a non-starter. For example, the following is not allowed:
public class MyPane : WindowPane
{
public static void Test(WindowPane p)
{
var service = p.GetService(typeof(Service));
// etc.
}
}
But you ask, "Isn't it allowed to access base class members from a derived class?" No, that actually isn't the rule. The rule is that you can access base class members from derived class only via a reference to the derived class, not from any base class reference directly. More details on this here. Your proposal amounts to allowing this kind of thing for an even larger class methods (i.e. methods that some other library author declares to be extension methods). Eric Lippert has written about this issue (here and here) in the past as well. Since cross hierarchy calls are blocked by the CLR, I would not expect something like this proposal to get implemented any time soon.

Thread doesn't work with void as ThreadStart [duplicate]

Is there any way to create a non-static thread method at .NET?
Show me code please.
The following code doesn't work:
ThreadStart ts = delegate { drawFloorAround(); };
public void drawFloorAround()
{
...
}
Gives this error -> "A field initializer cannot reference the non-static field, method, or property".
If I change the method do static, it works. But I don't want to.
... gives this error "A field initializer cannot reference the non-static field, method, or property".
Read the error message more carefully. It is telling you precisely what is wrong. A field initializer cannot reference a non-static method. That's because the compiler is trying to protect you from this bug:
class C
{
int foo;
int bar = GetBar();
public C(int newFoo)
{
this.foo = newFoo;
}
private int GetBar() { return this.foo + 1; }
}
You do "new C(123)". What is bar set to? If this were legal code then it would be set to 1, not 124. Why? Because first foo gets initialized to zero, then GetBar() gets called, then the constructor body sets this.foo to 123.
To prevent this bug it is simply illegal to reference an instance method or field in a field initializer.
Now, you might reasonably point out that in your code, you do not use the instance method, you only reference it. You never actually call it. This actually is safe. However, the rules of C# are designed to be simple and conservative; even though we could prove that this case is safe, we take the conservative, simple path and say that any reference to the instance in a field initializer is illegal.
If I change the method to static, it works.
Correct. In that case, the method does not depend upon instance state which has not yet been set up.
But I don't want to.
OK, then your only other choice is to stop using a field initializer. Put the initialization in the constructor; you then take responsibility for ensuring that the initialization does not accidentally use uninitialized state.
If you mean is it possible to start a thread with a non-static method - i.e. an instance method - then yes it is. But the same rules apply as to calling an instance method directly - you can only do it if you have an instance. For example, if you have an instance in a variable called foo then you can write this:
ThreadStart ts = delegate { foo.DrawFloorAround(); };
If you don't already have an instance that you can use, then you must first create one:
ThreadStart ts = delegate { new Foo().DrawFloorAround(); };
If you don't want to create an instance then your method probably should be static.
Yes
public class DoSomthing
{
public void Do()
{
Thread t = new Thread(DoInBackground);
t.Start();
}
public void DoInBackground()
{
// ....
}
}
Edit: the problem in the example code is that it is a field initialiser. Move this code to an explicit constructor:
ThreadStart ts;
public TypeName() {//constructor
ts = this.SomeMethod;
}
private void SomeMethod() {....}
Any method can act as a ThreadStart as log ad it takes no args and returns void. IMO the easiest option is a lambda or anon method as this allows closures:
ThreadStart ts = delegate {
someObj.DoSomething(x, y, "z");
};
But for an instance method that returns void and takes no args:
var obj = /* init obj */
ThreadStart ts = obj.SomeMethod;
Then
var thread = new Thread(ts);
Initializers run before constructors, so you have no instance to set it to. Set the value in your constructor and you should be okay.
class DoesNotWork {
public Action ts = Frob; // doesn't work, cannot access non-static method
void Frob() { }
}
class ThisIsFine {
public Action ts;
public ThisIsFine() { ts = Frob; }
void Frob();
}
It's important for anyone moving to C# from vb.net to note that the rules have changed between VB.net and C#. Under the vb.net (IMHO better) rules, initializers run between the call to mybase.new and the following statement of the constructor; it is permissible for field initializers to make reference to fields and properties of the current object. While this can cause problems if done carelessly, it allows variable initialization (and in some cases cleanup) to be handled at the same place in source code as the declaration. Anyone migrating to C# needs to recognize this difference in initializer handling. While it's possible in vb.net to properly dispose an iDisposable which is created in an initializer, that is not possible in C# without a severe kludge using a threadstatic variable.

Cannot convert lambda expression to type 'System.Delegate', Because it is not a delegate type

I define a dependency Property for my class1, which raise an event. I don't know why it give me this error "Cannot convert lambda expression to type 'System.Delegate'"
public static readonly DependencyProperty class1Property =
DependencyProperty.Register("class1Property", typeof(Class1), typeof(UserControl1), new PropertyMetadata(null));
public Class1 class1
{
get
{
return Dispatcher.Invoke((() => GetValue(class1Property)))as Class1;
}
set
{
Dispatcher.Invoke(new Action(() => { SetValue(class1Property, value); }));
}
}
Very simple Class1 code :
public class Class1
{
public delegate void myhandler(object sender, EventArgs e);
public event myhandler test;
public void connection()
{
test(this, new EventArgs());
}
}
IMHO, it is generally better to address cross-thread needs outside of individual properties. The properties themselves should be simple, just calling GetValue() and SetValue(). In other words, a property getter or setter should not need to call Dispatcher.Invoke() at all.
That said, in your code example, you are seeing the error you're asking about in the property getter, because the compiler does not have enough information to infer the correct delegate type. The Dispatcher.Invoke() method simply takes as its parameter the base class Delegate. But this class has no inherent signature, which the compiler would need in order to automatically translate the lambda expression to an appropriate anonymous method and matching delegate instance.
Note that there is not a similar error in the setter. This is because you have provided the delegate type explicitly, through the use of the Action type's constructor. If you change the getter code to look more like the setter, it will work.
There are a few different syntaxes you could choose from, but this seems closest to the syntax you seem to prefer, based on the setter:
get
{
return Dispatcher.Invoke(
new Func<object>(() => GetValue(class1Property))) as Class1;
}
See related discussion at e.g. Why must a lambda expression be cast when supplied as a plain Delegate parameter (if you search Stack Overflow for the error message you're seeing, you'll find a few related questions).

How to get non-static MethodInfo using method name (not in string, not searching in class type)

Consider following code:
public class Test
{
[System.AttributeUsage(System.AttributeTargets.Method)]
class MethodAttribute : System.Attribute
{
public MethodAttribute(System.Reflection.MethodInfo methodInfo)
{
}
}
public void Foo()
{
}
[Method(Test.Foo)] //< THIS IS THE IMPORTANT LINE
public void Boo()
{
}
}
I want to store MethodInfo instance of Foo in attribute of Boo, but problem is, that I cannot use Foo nor Test.Foo to get instance of MethodInfo. I can NOT use typeof(Test).GetMethod("Foo") (not my decision).
Important information:
Generated error is: error CS0120: An object reference is required to access non-static member `Test.Foo()'
I'm coding in Unity3D which is using Mono, not .Net. (more info http://docs.unity3d.com/410/Documentation/ScriptReference/MonoCompatibility.html )
Windows 7
Absolutely unimportant information:
Why I cannot use typeof(Test).GetMethod("Foo"): I'm not allowed. It's not in my power to change this decision. I can not. (Also, personally, I would like to avoid it anyway as it needs to do some lookup instead of getting statically the data. Also it won't be changed automatically during refactoring and will be checking run-time, not compile-time.)
Why I want to do this: later in code, I want to create a delegate of Boo() (this time normally, with an instance) and use in special even system or something. Before it's called, this attribute allows to setup method to be called in prepare for main event (it's optional, it can be null) and I know how to create a delegate when I have an object and a method info.
Why I cannot just provide both delegates when registering or something: because class containing these methods is not always the one who registers to event source, I need to keep the registration code as simple as possible. In other words, I want to avoid situation when person writing method responsible for connecting forgots to add this preparation delegate.
use expression :
static public class Metadata<T>
{
static public PropertyInfo Property<TProperty>(Expression<Func<T, TProperty>> property)
{
var expression = property.Body as MemberExpression;
return expression.Member as PropertyInfo;
}
}
var foo = Metadata<Test>.Property(test => test.Foo);

Casting through extension method

It was bothering me that there's so many places in code that follow this pattern:
int amount = 100;
Person person = new Employee();
var em = person as Employee;
if (em != null)
{
em.IncreaseSalary(amount);
}
So I created a small extension method:
public static class Extensions
{
public static void IfAssignable<T>(this object source, Action<T> run) where T : class
{
var target = source as T;
if (target != null)
{
run(target);
}
}
}
Now I could do:
int amount = 100;
Person person = new Employee();
person.IfAssignable<Employee>(e => e.IncreaseSalary(amount));
amount = 10;
I like this because it is more compact and e goes out of scope: I wouldn't be using it anyway if it were null.
Resharper then warns "access to modified closure". This is because the value of "amount" might change before the call gets executed I believe.
I don't think this is actually the case, since the code is executed synchronously directly. Am I missing something here? The fix to copy to a temporary value before executing "IncreaseSalary" defeats the purpose of the extension.
Edit: Clarification; I (believe I) know what this warning is trying to say. If I'd be executing code later (meaning asynchronously, or subscribing to an event) and use one of the values passed in implicitly from the outer scope, the warning would be right.
Additionally, this extension method is meant to be generic. I realize I could add any amount of extension methods to cater for any amount and types of parameters (pass them explicitly instead), pass those in through the method signature, and make this work. The idea behind the extension method is to be generically applicable though (except for asynchronous calls, event subscribtions, but that applies to all lambda's).
ReSharper is correct to warn you about you possibly modifying a captured variable, because it doesn't know what what you're doing with your lambda. In your case, the lambda is executed immediately, so there are no side effects from modifying the parameter.
Which is why you can instruct ReSharper that your lambda expression is immediately handled, by using the [InstantHandle] code annotation attribute, by applying it on your Action<T> parameter:
public static void IfAssignable<T>(this object source,
[InstantHandle] Action<T> run) where T : class
{
var target = source as T;
if (target != null)
{
run(target);
}
}
And the warning will disappear!
You will need to add the code annotations file to your project. You can do this by going into ReSharper Options, then select Code Inspection → Code Annotations. Press the Copy default implementation to clipboard, and paste the contents into a new file. If you change the namespace of the annotation attributes (default is JetBrains.Annotations, you will need to add the new namespace to the settings in the Code Annotations page in Options.
You can avoid it by using additional 'state' parameter:
public static class Extensions
{
public static void IfAssignable<T, TState>(this object source, Action<T, TState> run, TState state) where T : class
{
var target = source as T;
if (target != null)
{
run(target, state);
}
}
}
And then use it that way:
int amount = 100;
Person person = new Employee();
person.IfAssignable<Employee>((e, amount_) => e.IncreaseSalary(amount_), amount);
amount = 10;
That's also a way to avoid type/memory leaks and other strange bugs.

Categories

Resources