简体   繁体   中英

Is there a way to constrain anonymous function parameter's scope?

I have a method that takes an anonymous function parameter. This function's parameter is provided by a local variable.

public void DoSomething<T>(Action<T> method) where T : new()
{
    T instance = new T();
    method.Invoke(instance);
}

I want to prevent creating a closure. Local variable should go out of scope when DoSomething<T> is finished. Is there a way to constrain it at compile time?

Here's the situation I want to avoid:

Foo capturedInstance = null;
DoSomething<Foo>(item => capturedInstance = item);
capturedInstance.Call();

Unfortunately*, that's not possible. You have little to no control over what a method does with its arguments. It would be possible to work around if you weren't using generic types, but you are, so just don't worry about that kind of situation. (I hope you don't have to.)


* Actually, I consider it "fortunately". This isn't C++ we're talking about here.

If T were a struct, it would be possible for code which held a field of type T or an array of type T[] to pass the field or an array element as a ref parameter to an outside method; that method would be able to operate directly and efficiently on that field or array slot without having to make temporary copies of the struct, but once the method returned the type holding the field or array could be confident that outside code could no longer access that slot. Outside could have made a copy of the field or element's contents, of course, but it won't be able to change the original unless or until the type holding the struct again exposes it to outside code.

Unfortunately, if the T is a mutable class, exposing a reference will allow outside code to promiscuously copy and pass around that reference forevermore. For that reason, mutable classes are much worse data holders than mutable structs. If one wants to allow outside code to make use of a class without exposing a direct reference, it's necessary to create a wrapper class and interface. Unfortunately, there's no way of doing this without either using a truly horrible amount of duplicated code, or else using Reflection to generate wrappers at run-time.

I think your code already does what you want. The delegate representing the lambda item => capturedInstance = item is passed only to DoSomething<Foo> , and that reference is not handed out to anybody else. So, the delegate would go out of scope when the containing method finishes. And so will the local variable that is captured by the lambda expression. Only if you are passing around a reference to the delegate, you will not get the behavior you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM