Exception: DataAnalysis.Reference+<>c__DisplayClass4 is not serializable - c#

I am trying to serialize objects of class Reference at the end of my program. A serialization exception is thrown, which complains that "DataAnalysis.Reference+<>c__DisplayClass4" is not marked as serializable.
Initially I had the two delegates without the Serializable attribute, so I gave it a try, but it didn't change anything. The classes Cacheable and Operation are already marked as Serializable - and in fact the serialization of the both of them worked perfectly fine before I introduced the Reference class.
I don't even know what c__DisplayClass4 means. So I am sorry, but I don't know what other parts of my 1 megabytes+ source code to post here to help you solve the problem, because in the end I would be posting everything.
As I said, everything worked fine before introducing the Reference class. So I am hoping the problem is somehow localized to it.
using System;
using System.Reflection;
namespace DataAnalysis
{
/// <summary>
/// Description of Reference.
/// </summary>
[Serializable]
public class Reference
{
[Serializable]
public delegate void ReferenceSetter(Operation op, Cacheable c);
[Serializable]
public delegate Cacheable ReferenceGetter(Operation op);
readonly ReferenceGetter refGetter;
readonly ReferenceSetter refSetter;
public Reference(ReferenceGetter getter, ReferenceSetter setter)
{
refGetter = getter;
refSetter = setter;
}
public Reference(FieldInfo operationField)
{
refGetter = (op => (Cacheable)operationField.GetValue(op));
refSetter = ((op, value) => operationField.SetValue(op, value));
}
public Cacheable this[Operation op]
{
get {return refGetter(op);}
set {refSetter(op, value);}
}
}
}
Edit: I have chosen taffer's first solution (avoid using the FieldInfo inside a delegate):
public class Reference
{
public delegate void ReferenceSetter(Operation op, Cacheable c);
public delegate Cacheable ReferenceGetter(Operation op);
readonly FieldInfo opField;
readonly ReferenceGetter refGetter;
readonly ReferenceSetter refSetter;
public Reference(ReferenceGetter getter, ReferenceSetter setter)
{
refGetter = getter;
refSetter = setter;
}
public Reference(FieldInfo operationField)
{
opField = operationField;
}
public Cacheable this[Operation op]
{
get
{
if (opField != null) return (Cacheable)opField.GetValue(op);
else return refGetter(op);
}
set
{
if (opField != null) opField.SetValue(op, value);
else refSetter(op, value);
}
}
}
Not polished yet, I will probably finally use an abstract Reference class with two implementations. But the principle becomes clear.

You get the error because of the way you initialize your fields in the second constructor:
public Reference(FieldInfo operationField)
{
// operationField is captured in the lambda below, which causes to generate an inner class
// where operationField will be a field so can be accessed by the method of the lambda body
refGetter = (op => (Cacheable)operationField.GetValue(op));
refSetter = ((op, value) => operationField.SetValue(op, value));
}
Solution 1:
Do not capture locals and parameters of the enclosing method in the lambda. The field should rather be a parameter of the delegate.
Solution2:
Implement ISerializable and provide a custom serialization:
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("getter", refGetter);
info.AddValue("setter", refSetter);
}
// the special constructor needed for deserialization
private Reference(SerializationInfo info, StreamingContext context)
{
refGetter = (ReferenceGetter)info.GetValue("getter", typeof(ReferenceGetter));
refSetter = (ReferenceSetter)info.GetValue("setter", typeof(ReferenceSetter));
}
Please note that deserializing delegates of non-static methods can be problematic. Maybe you should check the Delegate.Method property in GetObjectData and throw an exception if the setter or getter is an instance method.

Related

IExtenderProvider add just some properties depending on object type

I'm having an issue and I don't know if this is indeed doable (if there's a "hacky" way, I'm all up for it, but I haven't found one).
I have an IExtenderProvider component that I'm using to have my own UITypeEditor for some properties on third-party controls (which I can't change, for obvious reasons).
These controls don't necessarily inherit from the same base (and if they do, the base doesn't necessarily have the properties I want to extend, and those are defined in the same class).
So, imagine for example I want to make an alternative property for the properties Image, Glyph, LargeGlyph, SmallGlyph on them.
So I have something like:
[ProvideProperty("LargeGlyphCustom", typeof (object))]
[ProvideProperty("GlyphCustom", typeof(object))]
[ProvideProperty("SmallImageCustom", typeof(object))]
[ProvideProperty("LargeImageCustom", typeof(object))]
[ProvideProperty("ImageCustom", typeof(object))]
public class MyImageExtender : Component, IExtenderProvider
{
private readonly Type[] _extendedTypes =
{
typeof (OtherControl),
typeof (SomeOtherControl),
typeof (AControl),
typeof (AButton)
};
bool IExtenderProvider.CanExtend(object o)
{
if (!DesignMode) return false;
return _extendedTypes.Any(t => t.IsInstanceOfType(o));
}
// Implement the property setter and getter methods
}
So far, so good. I can see my properties on the controls of the types I'm expecting.
However, these are replacements (just to change the UITypeEditor) of properties in the control.
The problem with my approach is that I see all of the extended properties in all of the extended types.
Say, if AButton only has Image, I only want to see ImageCustom and not SmallImageCustom, LargeImageCustom, etc.
So my approach was to do this:
[ProvideProperty("LargeGlyphCustom", typeof (OtherControl))]
// other properties
[ProvideProperty("ImageCustom", typeof(AButton))]
public class MyImageExtender : Component, IExtenderProvider
// ...
This seemed to work fine, and now I only see ImageCustom on AButton, and LargeGlyphCustom on OtherControl.
Now the problem is, if I want to show ImageCustom in both AButton and OtherControl, I had thought of doing this:
[ProvideProperty("ImageCustom", typeof(AButton))]
[ProvideProperty("ImageCustom", typeof(OtherControl))]
public class MyImageExtender : Component, IExtenderProvider
This doesn't work though, I only get to see ImageCustom on AButton, but not on OtherControl.
Decompiling the sources for ProvidePropertyAttribute, the reason this happens is "arguably" clear. It internally creates a TypeId, which I suspect is what the WinForms designer is using like this:
public override object TypeId
{
get
{
return (object) (this.GetType().FullName + this.propertyName);
}
}
Which makes the TypeId be "ProvidePropertyAttributeImageCustom", so it can't differentiate between the different receiver types.
I'm going to test deriving ProvidePropertyAttribute and create a different TypeId since it seems overridable, but I expect the winforms designer expect the specific ProvidePropertyAttribute type and not a derived one (the winforms designer is picky with these things).
Ouch, ProvidePropertyAttribute is sealed so I can't derive and make my custom TypeId, it seems (not that I had high hopes that this would work at all)
In the meantime, anyone has ever done something like this and know something I could use?
I know this is a quick answer, but this has been driving me nuts for a few days, so I've gone a different route which seems to work just fine.
Since the target goal (as I explained on my question) was to change the UITypeEditor on some properties, I've made a non-visual component that overrides the attributes (using a custom TypeDescriptor) on those properties, and assign my custom UITypeEditor there.
I used this answer as a base for implementing the property-overriding TypeDescriptor.
Update
For the record, the solution provided in the linked answer worked, however it had a problem where the TypeDescriptionProvider would get picked up for derived classes, however the returned TypeDescriptor would only return the properties for the base object (the one for which you passed in the parent TypeDescriptor), causing havok in things like the winforms designer.
I made an all purpose property-overrider TypeDescriptionProvider. So far, it has worked just fine. Here's the implementation. See the linked answer for an explanation of where did this come from:
The provider:
internal class PropertyOverridingTypeDescriptionProvider : TypeDescriptionProvider
{
private readonly Dictionary<Type, ICustomTypeDescriptor> _descriptorCache = new Dictionary<Type, ICustomTypeDescriptor>();
private readonly Func<PropertyDescriptor, bool> _condition;
private readonly Func<PropertyDescriptor, Type, PropertyDescriptor> _propertyCreator;
public PropertyOverridingTypeDescriptionProvider(TypeDescriptionProvider parentProvider, Func<PropertyDescriptor, bool> condition, Func<PropertyDescriptor, Type, PropertyDescriptor> propertyCreator) : base(parentProvider)
{
_condition = condition;
_propertyCreator = propertyCreator;
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
lock (_descriptorCache)
{
ICustomTypeDescriptor returnDescriptor;
if (!_descriptorCache.TryGetValue(objectType, out returnDescriptor))
{
returnDescriptor = CreateTypeDescriptor(objectType);
}
return returnDescriptor;
}
}
private ICustomTypeDescriptor CreateTypeDescriptor(Type targetType)
{
var descriptor = base.GetTypeDescriptor(targetType, null);
_descriptorCache.Add(targetType, descriptor);
var ctd = new PropertyOverridingTypeDescriptor(descriptor, targetType, _condition, _propertyCreator);
_descriptorCache[targetType] = ctd;
return ctd;
}
}
This is the actual TypeDescriptor:
internal class PropertyOverridingTypeDescriptor : CustomTypeDescriptor
{
private readonly ICustomTypeDescriptor _parent;
private readonly PropertyDescriptorCollection _propertyCollection;
private readonly Type _objectType;
private readonly Func<PropertyDescriptor, bool> _condition;
private readonly Func<PropertyDescriptor, Type, PropertyDescriptor> _propertyCreator;
public PropertyOverridingTypeDescriptor(ICustomTypeDescriptor parent, Type objectType, Func<PropertyDescriptor, bool> condition, Func<PropertyDescriptor, Type, PropertyDescriptor> propertyCreator)
: base(parent)
{
_parent = parent;
_objectType = objectType;
_condition = condition;
_propertyCreator = propertyCreator;
_propertyCollection = BuildPropertyCollection();
}
private PropertyDescriptorCollection BuildPropertyCollection()
{
var isChanged = false;
var parentProperties = _parent.GetProperties();
var pdl = new PropertyDescriptor[parentProperties.Count];
var index = 0;
foreach (var pd in parentProperties.OfType<PropertyDescriptor>())
{
var pdReplaced = pd;
if (_condition(pd))
{
pdReplaced = _propertyCreator(pd, _objectType);
}
if (!ReferenceEquals(pdReplaced, pd)) isChanged = true;
pdl[index++] = pdReplaced;
}
return !isChanged ? parentProperties : new PropertyDescriptorCollection(pdl);
}
public override object GetPropertyOwner(PropertyDescriptor pd)
{
var o = base.GetPropertyOwner(pd);
return o ?? this;
}
public override PropertyDescriptorCollection GetProperties()
{
return _propertyCollection;
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return _propertyCollection;
}
}
And here's how you use it. I've commented this:
private void ChangeTypeProperties(Type modifiedType, params string[] propertyNames)
{
// Get the current TypeDescriptionProvider
var curProvider = TypeDescriptor.GetProvider(modifiedType);
// Create a replacement provider, pass in the parent, this is important
var replaceProvider = new PropertyOverridingTypeDescriptionProvider(curProvider,
// This the predicate that says wether a `PropertyDescriptor` should be changed
// Here we are changing only the System.Drawing.Image properties,
// either those whose name we pass in, or all if we pass none
pd =>
typeof (System.Drawing.Image).IsAssignableFrom(pd.PropertyType) &&
(propertyNames.Length == 0 || propertyNames.Contains(pd.Name)),
// This our "replacer" function. It'll get the source PropertyDescriptor and the object type.
// You could use pd.ComponentType for the object type, but I've
// found it to fail under some circumstances, so I just pass it
// along
(pd, t) =>
{
// Get original attributes except the ones we want to change
var atts = pd.Attributes.OfType<Attribute>().Where(x => x.GetType() != typeof (EditorAttribute)).ToList();
// Add our own attributes
atts.Add(new EditorAttribute(typeof (MyOwnEditor), typeof (System.Drawing.Design.UITypeEditor)));
// Create the new PropertyDescriptor
return TypeDescriptor.CreateProperty(t, pd, atts.ToArray());
}
);
// Finally we replace the TypeDescriptionProvider
TypeDescriptor.AddProvider(replaceProvider, modifiedType);
}
Now, for the requirements of my question, I've created a simple drop-in component which I drop on the base form, which does just this:
public class ToolbarImageEditorExtender : Component
{
private static bool _alreadyInitialized;
public ToolbarImageEditorExtender()
{
// no need to reinitialize if we drop more than one component
if (_alreadyInitialized)
return;
_alreadyInitialized = true;
// the ChangeTypeProperties function above. I just made a generic version
ChangeTypeProperties<OtherControl>(nameof(OtherControl.Glyph), nameof(OtherControl.LargeGlyph));
ChangeTypeProperties<AButton>(nameof(AButton.SmallImage), nameof(AButton.LargeImage));
// etc.
}
}
So far, it has worked wonders.

a disposed closure has a strange behavior

I have a disposable class like this :
public class Person:IDisposable
{
public string Name{get;set;}
public void Dispose()
{}
}
and here's a set of extensions methods that returns a default value if the caller is null:
static class Extensions
{
public class Option<T>
{
private readonly Func<T> _resultGetter;
public bool HasValue { get; }
public Option(Func<T> resultGetter, bool hasValue)
{
_resultGetter = resultGetter;
HasValue = hasValue;
}
public T Value => _resultGetter();
}
public static Option<TResult> SafeGetter<T, TResult>(this T self, Func<T, TResult> getter, Func<TResult> defaultGetter = null) where T : class
{
defaultGetter = defaultGetter ?? (() => default(TResult));
return new Option<TResult>(self == null ? defaultGetter :()=> getter(self),self!=null);
}
}
As you can see the SafeGetter method returns an Option object that has a getter function that has a self parameter as closure.
So to test the getter function after an object is disposed I wrote a test like this :
public void SafeGetterDisposableTest()
{
Extensions.Option<string> nameGetter;
using (var john = new Person { Name = "John" })
{
nameGetter = john.SafeGetter(x => x.Name);
}
Console.WriteLine(nameGetter.Value);
}
as you can see I have got the Option object and call it after john is disposed. I thought that I would get an exception but to my surprise the test is working.
Why this is happening ? Does this code somehow introduce memory leak ?
I thought that I would get an exception but to my surprise the test is
working.
You do not receive an ObjectDisposedException (or any other exception for that matter) just by simply implementing IDisposable. Your Dispose method is empty, and doesn't alter the object even after it has been called by your using statement. If you alter it to throw an exception in your getter after the object has been disposed, you'll get an exception. Otherwise, nothing will happen.
It is a convention that IDisposable objects be implemented such that they'll throw an exception when their members are accesses after they've been disposed. This is not behavior of the language. If your disposable object actually had an umanaged resource that it was using, and then cleaned up, then presumably an operation you perform after its been disposed wouldn't work properly, even if you didn't explicitly throw, hence the convention.

Return instance using reflection in C#

A sample code I tried to return an instance of class is given below.
public object getConstructorclass(int i)
{
if(i==1)
{
Type type = Type.GetType("test1");
}else
{
Type type = Type.GetType("test2");
}
return Activator.CreateInstance(type);
}
var objcls = getConstructorclass(1);
objcls.callclass();//error occured
How can I mention the class type here since the type is not known at compile time but it will decided at runtime.In the above example i just pass a value 1 (it can be anything and that class will be called accordingly), and the class test1 called.
here I will get an error on the line objcls.callclass(), because objcls is an object instance that doesn't have a callclass()method.
How can I restructure this piece of code? My aim is if I mention a class in the getConstructorclass() method, an object should be returned so as to use it in the further code to invoke the members of that class.
If you know that your classes will have this method, you should use a common interface for them and implement it accordingly. Then you will work with classes that you have made sure it will work.
It would look like this
IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
objcls.callclass();
else
// we failed miserably and should do something about it
I don't think you should use some generic object returning constructor based on an int variable, if your classes don't have anything in common. It's really weird to handle it like this and it may lead to various problems (some of which you're currently already experiencing). Generic class constructors make sense if the classes are somewhat related and you can predict the outcome, but to create a do-it-all method.. Not so sure about correctness of such approach.
Anyway, if you insist (not recommended, but as you wish), you can create some checks for a type like this:
var createdObject = getConstructorclass(1);
if (createdObject is MyClass1)
{
var specificObject = (MyClass1)createdObject;
specificObject.callMethod1();
}
else if (createdObject is MyClass2)
{
var specificObject = (MyClass2)createdObject;
specificObject.callSomeOtherMethod();
}
...
But it gets very error prone soon, refactoring will probably be a nightmare etc., but it's your call..
Or you maybe can use solution from pwas, but to me it seems unnecessarily complicated for such a basic task. Looks nice and all, but it still returns only the type "object", so it doesn't really solve your specific problem.
Also, to address one issue I'm not sure you understand - you've already created the instance, you just return type object. That is why you can't call any specific methods on this object, because first you have to cast it to something, that actually has that method and make sure the cast can be done (inheritance etc).
If interface solution (see other answers) is enough, don't look at this answer. When you can't use common base class / interface and you still want call members, you can use solution with is keyword (and check types). Instead of writing many ifs for each case, you can use fluent API:
object obj = this.getConstructorclass();
obj.StronglyInvoke()
.When<int>(value => Console.WriteLine("Got {0} as int", value))
.When<string>(value => Console.WriteLine("Got {0} as string", value))
.OnFail(() => Debug.Write("No handle."))
.Invoke();
Solution:
public class GenericCaller
{
private IList<GenericInvoker> invokers = new List<GenericInvoker>();
private readonly object target;
private Action failAction;
public GenericCaller(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this.target = target;
}
public GenericCaller OnFail(Action fail)
{
this.failAction = fail;
return this;
}
public GenericCaller When<T>(Action<T> then)
{
if (then == null)
{
throw new ArgumentNullException("then");
}
var invoker = new GenericInvoker<T>(this.target, then);
this.invokers.Add(invoker);
return this;
}
public void Invoke()
{
if (this.invokers.Any(invoker => invoker.Invoke()))
{
return;
}
if (this.failAction == null)
{
throw new InvalidOperationException("Handler not found");
}
this.failAction();
}
public abstract class GenericInvoker
{
protected readonly object target;
protected GenericInvoker(object target)
{
this.target = target;
}
public abstract bool Invoke();
}
public class GenericInvoker<T> : GenericInvoker
{
private readonly Action<T> then;
public GenericInvoker(object target, Action<T> then)
: base(target)
{
this.then = then;
}
public override bool Invoke()
{
if (this.target.GetType() == typeof(T))
{
this.then((T)this.target);
return true;
}
return false;
}
}
}
public static class Extensions
{
public static GenericCaller StronglyInvoke(this object o)
{
return new GenericCaller(o);
}
}
Remeber - it would be more elegant to use common interface (as other answers say) - my is only alternative way.
Declare your variable as dynamic
dynamic objcls = getconstrorclass();
Using this the will be determined at run-time, whatever the getconstrorclass method returns. You can access any member of the type and you won't get any error at compile-time. But if you try to access a member which doesn't exists you will get a RuntimeBinderException at runtime.
I would recommend using an interface and restricting the classes that you can instantiate this way to only those that implement the interface.
public interface IMyInterface
{
void callclass();
}
public <T> getConstructorClass()
{
T instance;
Type type = Type.GetType("test1");
// instance will be null if the object cannot be cast to type T.
instance = Activator.CreateInstance(type) as T;
return T;
}
IMyInterface objcls = getConstructorClass<IMyInterface>();
if(null != objcls)
{
objcls.callclass();
}
not sure what you want to achieve in the end, but this looks like a job for "Dependency Injection" - here is a nice sample using autofac

Adding generic properties to an object without having to cast them later?

I have an object, MySession, that has a hashtable for storing arbitrary properties with arbitrary types. The relevant part of the object definition is:
public class MySession
{
private Hashtable _sessionVars;
///
/// Set and retrieve session variables ala the traditional session managers.
/// So, SessionObject["var1"] can be used to set or retrieve a value for var1.
///
/// Name of the variable to access.
/// An object that was stored in the session under key.
public object this[string key] {
get {
if (_sessionVars.ContainsKey(key)) {
return this._sessionVars[key];
}
return null;
}
set {
if (this._sessionVars.ContainsKey(key)) {
this._sessionVars.Remove(key);
}
this._sessionVars[key] = value;
}
}
}
The annoying thing is that I have to properly cast the properties when I want to use them. For example:
MySession session = new MySession();
if ( (bool)session["valid"] == true ) { /* do something fun */ }
I would rather be able to do:
MySession session = new MySession();
if ( session["valid"] == true ) { /* do something fun */ }
Is it possible to do this in C#? If so, how?
Update: I do not want to use explicit methods for accessing the properties. The point is to be able to access them as simply as possible. Not like session.GetProperty(name, type) or something.
If you think carefully, you will realize that this is inherently impossible.
What if you write session[someTextbox.Text]?
What if you assign two different types to the same identifier?
Compiling such code would involve solving the halting problem to figure out what type each string would have.
Instead, you could make a strongly-typed wrapper class around HttpContext.Current.Session with properties that include casts in their getters.
If you are using .Net Framework 4.0 then you can do it by deriving your MySession class from DynamicObject and overriding the necessary methods.
Here is the code:
public class MySession : DynamicObject
{
//Why not use Dictionary class?
private Hashtable _sessionVars = new Hashtable();
public override bool TrySetMember(SetMemberBinder binder, object value)
{
this[binder.Name] = value;
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
}
//You can make it private so that users do not use strings directly.
public object this[string key]
{
get
{
if (_sessionVars.ContainsKey(key))
{
return this._sessionVars[key];
}
return null;
}
set
{
if (this._sessionVars.ContainsKey(key))
{
this._sessionVars.Remove(key);
}
this._sessionVars[key] = value;
}
}
}
And this how you use it:
dynamic ses = new MySession();
ses.number = 5;
ses.boolean = true;
Console.WriteLine(ses.number > 4);
if (ses.boolean)
{
Console.WriteLine(ses.number - 1);
}
Console.ReadKey();
No need for casting or using string to access the new fields! If you are using Resharper you will get intellisense for existing fields too. If you need more functionality you can override other members too.
I personally end up having to handle the scenario where the session variable hasn't been set yet. Therefore, I end up with a method that looks like this:
public class MySession
{
...
public T GetValue<T>(string key, T defaultValue)
{
return _sessionVars.ContainsKey(key) ? this._sessionVars[key] as T : defaultValue;
}
}
Then T can be inferred. It can then be called like this (no casting required):
if (mySession.GetValue("valid", false))
{
// fun stuff here
}
I'm not really sure is "as T" works. If not, you can cast it to (T) done that before. "as T" would be nice if you've got inherited classes and such.
I typically derive off a class like mySession and call base.GetValue() in property getters I expose off the derived class.
If you're passing string (or any sort of object) keys, then it's impossible to do; the indexer method can only return one specific type, so you couldn't possible have it return a string or a double, for instance.
There are a couple of options: one, if this is a limited-scope class that doesn't need the flexibility of arbitrary keys, then you can just add explicit properties--maybe just for commonly used properties if you want to still be able to fall back on the object-returning indexer.
Or, you could add a generic Get method, like so:
public T GetValue<T>(object key) {
if(_hashSet[key] is T) {
return (T)_hashSet[key];
}
throw new InvalidCastException();
}
That doesn't get you much, though, since you'll still have to specify the type name, you're just moving it from the cast to the generic parameter.
EDIT: Of course, how you want to handle invalid casts is up to you, but throwing the exception mimics the behavior of the direct cast. As someone mentioned in another answer, if you also specify a parameter of type T in the signature, then it will get the correct type from that parameter.
Easy and best way to add session
public static void Add<T>(string key, T value)
{
var current = HttpContext.Current;
if (current == null) return;
current.Session.Add(key, value);
}
Example
public Model User
{
private string searchText
{
get { return SessionHelper.Get<string>("searchText"); }
set { SessionHelper.Add("searchText", value); }
}
}

Store a reference to a value type?

I am writing a "Monitor" object to facilitate debugging of my app. This Monitor object can be accessed at run time from an IronPython interpreter. My question is, is it possible in C# to store a reference to a value type? Say I have the following class:
class Test
{
public int a;
}
Can I somehow store a "pointer" to "a" in order to be able to check it's value anytime? Is it possible using safe and managed code?
Thanks.
You cannot store a reference to a variable in a field or array. The CLR requires that a reference to a variable be in (1) a formal parameter, (2) a local, or (3) the return type of a method. C# supports (1) but not the other two.
(ASIDE: It is possible for C# to support the other two; in fact I have written a prototype compiler that does implement those features. It's pretty neat. (See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/ for details.) Of course one has to write an algorithm that verifies that no ref local could possibly be referring to a local that was on a now-destroyed stack frame, which gets a bit tricky, but its doable. Perhaps we will support this in a hypothetical future version of the language. (UPDATE: It was added to C# 7!))
However, you can make a variable have arbitrarily long lifetime, by putting it in a field or array. If what you need is a "reference" in the sense of "I need to store an alias to an arbitrary variable", then, no. But if what you need is a reference in the sense of "I need a magic token that lets me read and write a particular variable", then just use a delegate, or a pair of delegates.
sealed class Ref<T>
{
private Func<T> getter;
private Action<T> setter;
public Ref(Func<T> getter, Action<T> setter)
{
this.getter = getter;
this.setter = setter;
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
...
Ref<string> M()
{
string x = "hello";
Ref<string> rx = new Ref<string>(()=>x, v=>{x=v;});
rx.Value = "goodbye";
Console.WriteLine(x); // goodbye
return rx;
}
The outer local variable x will stay alive at least until rx is reclaimed.
No - you can't store a "pointer" to a value type directly in C#.
Typically, you'd hold a reference to the Test instance containing "a" - this gives you access to a (via testInstance.a).
Here is a pattern I came up with that I find myself using quite a bit. Usually in the case of passing properties as parameters for use on any object of the parent type, but it works just as well for a single instance. (doesn't work for local scope value types tho)
public interface IValuePointer<T>
{
T Value { get; set; }
}
public class ValuePointer<TParent, TType> : IValuePointer<TType>
{
private readonly TParent _instance;
private readonly Func<TParent, TType> _propertyExpression;
private readonly PropertyInfo _propInfo;
private readonly FieldInfo _fieldInfo;
public ValuePointer(TParent instance,
Expression<Func<TParent, TType>> propertyExpression)
{
_instance = instance;
_propertyExpression = propertyExpression.Compile();
_propInfo = ((MemberExpression)(propertyExpression).Body).Member as PropertyInfo;
_fieldInfo = ((MemberExpression)(propertyExpression).Body).Member as FieldInfo;
}
public TType Value
{
get { return _propertyExpression.Invoke(_instance); }
set
{
if (_fieldInfo != null)
{
_fieldInfo.SetValue(_instance, value);
return;
}
_propInfo.SetValue(_instance, value, null);
}
}
}
This can then be used like so
class Test
{
public int a;
}
void Main()
{
Test testInstance = new Test();
var pointer = new ValuePointer(testInstance,x=> x.a);
testInstance.a = 5;
int copyOfValue = pointer.Value;
pointer.Value = 6;
}
Notice the interface with a more limited set of template arguments, this allows you to pass the pointer to something that has no knowledge of the parent type.
You could even implement another interface with no template arguments that calls .ToString on any value type (don't forget the null check first)
You can create ref-return delegate. This is similar to Erik's solution, except instead of getter and setter it use single ref-returning delegate.
You can't use it with properties or local variables, but it returns true reference (not just copy).
public delegate ref T Ref<T>();
class Test
{
public int a;
}
static Ref<int> M()
{
Test t = new Test();
t.a = 10;
Ref<int> rx = () => ref t.a;
rx() = 5;
Console.WriteLine(t.a); // 5
return rx;
}
You can literally take a pointer to a value type using usafe code
public class Foo
{
public int a;
}
unsafe static class Program
{
static void Main(string[] args)
{
var f=new Foo() { a=1 };
// f.a = 1
fixed(int* ptr=&f.a)
{
*ptr=2;
}
// f.a = 2
}
}
class Test
{
private int a;
/// <summary>
/// points to my variable type interger,
/// where the identifier is named 'a'.
/// </summary>
public int A
{
get { return a; }
set { a = value; }
}
}
Why put yourself through all that hassle of writing complicated code, declaring identifiers everywhere linking to the same location? Make a property, add some XML code to help you outside the class, and use the properties in your coding.
I don't know about storing a pointer, don't think it's possible, but if you're just wanting to check its value, the safest way to my knowledge is to create a property of the variable. At least that way you can check its property at any time and if the variable is static, you wouldn't even have to create an instance of the class to access the variable.
Properties have a lot of advantages; type safety is one, XML tags another. Start using them!

Categories