context: // 
  // FieldValueReference.cs
  //  
  // Authors: Lluis Sanchez Gual <lluis@novell.com>
  //          Jeffrey Stedfast <jeff@xamarin.com>
  // 
  // Copyright (c) 2009 Novell, Inc (http://www.novell.com)
  // Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
  // 
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  // 
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  using System;
  using System.Reflection;
  using Mono.Debugging.Evaluation;
  using Mono.Debugger.Soft;
  using Mono.Debugging.Client;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Mono.Debugging.Soft
  {
  	public class FieldValueReference: SoftValueReference
  	{
  		FieldInfoMirror field;
  		object obj;
  		TypeMirror declaringType;
  		ObjectValueFlags flags;
  		string vname;
  		FieldReferenceBatch batch;
  		
  		public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, FieldReferenceBatch batch = null)
  			: this (ctx, field, obj, declaringType, null, ObjectValueFlags.Field, batch)
  		{
  		}
  		
  		public FieldValueReference (EvaluationContext ctx, FieldInfoMirror field, object obj, TypeMirror declaringType, string vname, ObjectValueFlags vflags, FieldReferenceBatch batch = null): base (ctx)
  		{
  			this.field = field;
  			this.obj = obj;
  			this.declaringType = declaringType;
  			this.vname = vname;
  			this.batch = batch;
  			flags = vflags;
  
  			if (field.IsStatic)
  				this.obj = null;
  
  			var objectMirror = obj as ObjectMirror;
  			if (objectMirror != null)
  				EnsureContextHasDomain (objectMirror.Domain);
  
  			flags |= GetFlags (field);
  
  			if (obj is PrimitiveValue)
  				flags |= ObjectValueFlags.ReadOnly;
  		}
  
  		internal static ObjectValueFlags GetFlags (FieldInfoMirror field)
  		{
  			var flags = ObjectValueFlags.Field;
  
  			if (field.IsStatic)
  				flags |= ObjectValueFlags.Global;
  
  			if (field.IsPublic)
  				flags |= ObjectValueFlags.Public;
  			else if (field.IsPrivate)
  				flags |= ObjectValueFlags.Private;
  			else if (field.IsFamily)
  				flags |= ObjectValueFlags.Protected;
  			else if (field.IsFamilyAndAssembly)
  				flags |= ObjectValueFlags.Internal;
  			else if (field.IsFamilyOrAssembly)
  				flags |= ObjectValueFlags.InternalProtected;
  
  			return flags;
  		}
  		
  		public override ObjectValueFlags Flags {
  			get {
  				return flags;
  			}
  		}
  
  		public override string Name {
  			get {
  				return vname ?? field.Name;
  			}
  		}
  
  		public override object Type {
  			get {
  				return field.FieldType;
  			}
  		}
  		
  		public override object DeclaringType {
  			get {
  				return field.DeclaringType;
  			}
  		}
  
  		public override object Value {
  			get {
  				if (obj == null) {
  					// If the type hasn't already been loaded, invoke the .cctor() for types w/ the BeforeFieldInit attribute.
  					Context.Adapter.ForceLoadType (Context, declaringType);
  
  					return declaringType.GetValue (field, ((SoftEvaluationContext)Context).Thread);
  				} else if (obj is ObjectMirror) {
  					if (batch != null)
  						return batch.GetValue (field);
  					return ((ObjectMirror)obj).GetValue (field);
  				} else if (obj is StructMirror) {
  					StructMirror sm = (StructMirror)obj;
  					int idx = 0;
  					foreach (FieldInfoMirror f in sm.Type.GetFields ()) {
  						if (f.IsStatic) continue;
  						if (f == field)
  							break;
  						idx++;
  					}
  					return sm.Fields [idx];
  				} else if (obj is StringMirror) {
  					SoftEvaluationContext cx = (SoftEvaluationContext) Context;
  					StringMirror val = (StringMirror) obj;
  					FieldInfo rfield = typeof(string).GetField (field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  					return cx.Session.VirtualMachine.CreateValue (rfield.GetValue (val.Value));
  				} else {
  					SoftEvaluationContext cx = (SoftEvaluationContext) Context;
  					PrimitiveValue val = (PrimitiveValue) obj;
  					if (val.Value == null)
  						return null;
  					FieldInfo rfield = val.Value.GetType ().GetField (field.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  					return cx.Session.VirtualMachine.CreateValue (rfield.GetValue (val.Value));
  				}
  			}
  			set {
  				if (obj == null)
  					declaringType.SetValue (field, (Value)value);
  				else if (obj is ObjectMirror) {
  					if (batch != null)
  						batch.Invalidate ();
  					((ObjectMirror)obj).SetValue (field, (Value)value);
  				}
  				else if (obj is StructMirror) {
  					StructMirror sm = (StructMirror)obj;
  					int idx = 0;
  					foreach (FieldInfoMirror f in sm.Type.GetFields ()) {
  						if (f.IsStatic) continue;
  						if (f == field)
  							break;
  						idx++;
  					}
  					if (idx != -1) {
  						sm.Fields [idx] = (Value)value;
  						// Structs are handled by-value in the debugger, so the source of the object has to be updated
  						if (ParentSource != null && obj != null)
  							ParentSource.Value = obj;
  					}
  				}
  				else
  					throw new NotSupportedException ();
  			}
  		}
  
  		internal string [] GetTupleElementNames ()
  		{
  			return GetTupleElementNames (field.GetCustomAttributes (true));
  		}
  
  		internal static string [] GetTupleElementNames (CustomAttributeDataMirror [] attrs)
  		{
  			var attr = attrs.FirstOrDefault (at => at.Constructor.DeclaringType.Name == "TupleElementNamesAttribute");
  			if (attr == null)
  				return null;
  			var attributeValue = attr.ConstructorArguments.Single ().Value;
  			var array = attributeValue as ArrayMirror;
  			if (array == null)
  				return null;
  			var values = array.GetValues (0, array.Length);
  			if (!values.Any ())
  				return null;
  			var result = new string [values.Count];
  			for (int i = 0; i < result.Length; i++) {
  
gt: 				if (values [i] is StringMirror s)//other than string is null