ValueType object

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • colin

    ValueType object

    Hi,
    Im a bit confused about when you cast a value type to an object.
    I have a property grid wich stores the data and the defualt as
    objects.

    the data is limited to primitive types, structs and strings.
    the structs only have primitive types.

    however once ive set the data to the defualt,
    if the data is a struct then any edits change the defualt data as well
    wich was unexpected !

    however it doesnt happen for primitive types.

    I thought value types were always passed by value,
    does this mean an object is actually able to behave
    as a pointer to a struct ?

    I gues il have to identify if its a struct and copy it with reflection ?...
    but why is there not even Type.IsStruct ?
    would this be the same as !IsClass&&!IsIn terface&&!IsPri mitive ?

    Colin =^.^=


  • Marc Gravell

    #2
    Re: ValueType object

    I have a property grid wich stores the data and the defualt as
    objects.
    Well, you haven't really explained this setup... and unfortunately the
    devil is probably in the detail here... can you add more info?
    however once ive set the data to the defualt,
    if the data is a struct then any edits change the defualt data as well
    wich was unexpected !
    I'm guessing that your structs are "mutable" - i.e. you can edit them
    once created. This is almost always a big mistake; where "almost" means
    "it would take a long discussion to explain some borderline scenarios
    where it might just possibly make sense to have a mutable struct". In
    general, structs should be /immutable/ - i.e. once created they never
    change, but can be replaced (hence the need to provide CreateInstance
    etc on a TypeConverter).
    I thought value types were always passed by value,
    does this mean an object is actually able to behave
    as a pointer to a struct ?
    Yes; the term is "box"; when you box a value-type to an object, an
    object is created on the managed heap that encapsulates the value-type -
    *broadly* as though you had a class with a single field member (although
    it isn't really that).

    If you then give two different bits of code the same boxed copy, then
    they will be stomping all over each others values
    I gues il have to identify if its a struct and copy it with reflection ?...
    You can get the TypeConverter to do this for you; I'll knock up a demo...
    would this be the same as !IsClass&&!IsIn terface&&!IsPri mitive ?
    Well, I'd go for Type.IsValueTyp e

    Marc

    Comment

    • Marc Gravell

      #3
      Re: ValueType object

      Et voila; an "editable" immutable struct via PropertyGrid

      (quoted because it isn't actually an edit; it is a create)

      Marc

      using System.Componen tModel;
      using System.Windows. Forms;

      [TypeConverter(t ypeof(SomeStruc tConverter))]
      public struct SomeStruct
      {
      private readonly int foo;
      private readonly string bar;

      public int Foo { get {return foo;}}
      public string Bar { get {return bar;}}

      public SomeStruct(int foo, string bar)
      {
      this.foo = foo;
      this.bar = bar;
      }
      public override string ToString()
      {
      return string.Format(" {0}:{1}", Foo, Bar);
      }
      }

      sealed class SomeStructConve rter : ExpandableObjec tConverter
      {
      public override bool
      GetCreateInstan ceSupported(ITy peDescriptorCon text context)
      {
      return true;
      }
      public override object CreateInstance( ITypeDescriptor Context
      context, System.Collecti ons.IDictionary propertyValues)
      {
      return new SomeStruct((int )propertyValues["Foo"],
      (string)propert yValues["Bar"]);
      }

      // if you want to be able to edit the text directly
      // rather than via the sub-properties, then you need
      // to implement [Can]ConvertTo / [Can]ConvertFrom looking for
      // string; note that ConvertTo will use ToString by
      // default, so you just need [Can]ConvertFrom
      }

      class SomeType
      {
      private SomeStruct someValue;
      public SomeStruct SomeValue
      {
      get { return someValue; }
      set { someValue = value; }
      }
      }

      static class Program
      {
      static void Main()
      {
      Application.Ena bleVisualStyles ();
      using (Form form = new Form())
      using (PropertyGrid grid = new PropertyGrid())
      {
      grid.Dock = DockStyle.Fill;
      form.Controls.A dd(grid);
      grid.SelectedOb ject = new SomeType();
      Application.Run (form);
      }
      }
      }

      Comment

      • Marc Gravell

        #4
        Re: ValueType object

        Here you go; a mock up, just showing a possible setup... actually I
        switched to TypeDescriptor for the properties here for brevity, but in a
        real system I'd probably use ICustomTypeDesc riptor /
        TypeDescription Provider...

        using System;
        using System.Collecti ons.Generic;
        using System.Componen tModel;
        using System.Windows. Forms;

        [TypeConverter(t ypeof(FlexiObje ctConverter))]
        class FlexiObject
        {
        private readonly Dictionary<stri ng, objectvalues
        = new Dictionary<stri ng, object>(StringC omparer.Ordinal IgnoreCase);

        internal IEnumerable<Key ValuePair<strin g, object>Values
        {
        get { return values; }
        }

        public object this[string key]
        {
        get
        {
        object value;
        values.TryGetVa lue(key, out value);
        return value;
        }
        set
        {
        if (value == null)
        {
        values.Remove(k ey);
        }
        else
        {
        values[key] = value;
        }
        }
        }
        }
        class FlexiObjectConv erter : TypeConverter
        {
        public override bool GetPropertiesSu pported(ITypeDe scriptorContext
        context)
        {
        return true;
        }
        public override PropertyDescrip torCollection
        GetProperties(I TypeDescriptorC ontext context, object value, Attribute[]
        attributes)
        {
        FlexiObject obj = (FlexiObject)va lue;
        List<PropertyDe scriptorprops = new List<PropertyDe scriptor>();
        foreach (KeyValuePair<s tring, objectpair in obj.Values)
        {
        if (pair.Value != null)
        {
        props.Add(new
        FlexiPropertyDe scriptor(pair.V alue.GetType(), pair.Key));
        }
        }
        return new PropertyDescrip torCollection(p rops.ToArray(), true);
        }
        }
        class FlexiPropertyDe scriptor : PropertyDescrip tor
        {
        private readonly Type propertyType;
        public FlexiPropertyDe scriptor(Type propertyType, string name)
        : base(name, new Attribute[0])
        {
        this.propertyTy pe = propertyType;
        }
        public override bool IsReadOnly
        {
        get { return false; }
        }
        private FlexiObject GetFlexi(object component)
        {
        return (FlexiObject)co mponent;
        }
        public override object GetValue(object component)
        {
        return GetFlexi(compon ent)[Name];
        }
        public override void SetValue(object component, object value)
        {
        GetFlexi(compon ent)[Name] = value;
        }
        public override Type ComponentType
        {
        get { return typeof(FlexiObj ect); }
        }
        public override bool CanResetValue(o bject component)
        {
        return true;
        }
        public override void ResetValue(obje ct component)
        {
        GetFlexi(compon ent)[Name] = GetDefaultValue ();
        }
        public override Type PropertyType
        {
        get { return propertyType; }
        }
        public override bool ShouldSerialize Value(object component)
        {
        return !object.Equals( GetValue(compon ent), GetDefaultValue ());
        }
        private object GetDefaultValue () {
        Type type = PropertyType;
        if (type == typeof(string)) return "";
        if (type.IsValueTy pe) return Activator.Creat eInstance(type) ;
        return null;
        }
        }
        static class Program
        {
        [STAThread]
        static void Main()
        {
        FlexiObject obj = new FlexiObject();
        obj["Name"] = "Marc";
        obj["DOB"] = DateTime.Today;
        obj["ShoeSize"] = 9;
        obj["Icon"] = System.Drawing. SystemIcons.Shi eld;
        obj["FavColour"] = System.Drawing. Color.Red;
        obj["UriKind"] = System.UriKind. Relative;

        Application.Ena bleVisualStyles ();
        using (Form form = new Form())
        using (PropertyGrid grid = new PropertyGrid())
        {
        grid.Dock = DockStyle.Fill;
        form.Controls.A dd(grid);
        grid.SelectedOb ject = obj;
        Application.Run (form);
        }
        }
        }

        Comment

        • colin

          #5
          Re: ValueType object

          many thanks again :)

          I hadnt run into boxing before,
          I think I understand it now thanks,
          but primitive types dont seem to be affected.

          all the structs are just structs,
          and I have little control over them.

          the data in the structs does need to be edited though thats the whole point
          !

          the structs could be anywhere such as in an array, or in a class or another
          struct.

          the defualts however arnt intended to be edited,
          well at least not unintentionaly !

          ive gone for Type.IsValueTyp e &&!Type.IsPrimi tive.

          I cant beleive the amount of code thats gone into using this property grid
          so far,
          I realy wish id made my self a custom cell based control.

          rather than create even more code with a type converter,
          ive gone for the quick if dirty marshal way.

          int size=Marshal.Si zeOf(uDefaults. data);
          IntPtr ptr = Marshal.AllocHG lobal(size);
          Marshal.Structu reToPtr(uDefaul ts.data, ptr, true);
          udata.data=Mars hal.PtrToStruct ure(ptr, type);
          Marshal.FreeHGl obal(ptr);

          seems to work even if im a little uneasy about such code.
          although it will only work where the struct is initially a null object,
          this suits my needs. however editing fields of sub structs doesnt
          work with the boxing method, as it seems to create another copy.
          seems il have to use a typedreference, but that can only be used for
          the struct fields, its a shame it cant be used for the primitive fields too.

          Colin =^.^=

          "Marc Gravell" <marc.gravell@g mail.comwrote in message
          news:%23Nu%233f HpIHA.548@TK2MS FTNGP06.phx.gbl ...
          >I have a property grid wich stores the data and the defualt as
          >objects.
          >
          Well, you haven't really explained this setup... and unfortunately the
          devil is probably in the detail here... can you add more info?
          >
          however once ive set the data to the defualt,
          if the data is a struct then any edits change the defualt data as well
          wich was unexpected !
          >
          I'm guessing that your structs are "mutable" - i.e. you can edit them once
          created. This is almost always a big mistake; where "almost" means "it
          would take a long discussion to explain some borderline scenarios where it
          might just possibly make sense to have a mutable struct". In general,
          structs should be /immutable/ - i.e. once created they never change, but
          can be replaced (hence the need to provide CreateInstance etc on a
          TypeConverter).
          >
          >I thought value types were always passed by value,
          >does this mean an object is actually able to behave
          >as a pointer to a struct ?
          >
          Yes; the term is "box"; when you box a value-type to an object, an object
          is created on the managed heap that encapsulates the value-type -
          *broadly* as though you had a class with a single field member (although
          it isn't really that).
          >
          If you then give two different bits of code the same boxed copy, then they
          will be stomping all over each others values
          >
          >I gues il have to identify if its a struct and copy it with reflection
          >?...
          You can get the TypeConverter to do this for you; I'll knock up a demo...
          >
          >would this be the same as !IsClass&&!IsIn terface&&!IsPri mitive ?
          Well, I'd go for Type.IsValueTyp e
          >
          Marc

          Comment

          • Marc Gravell

            #6
            Re: ValueType object

            There is no special reason that primatives aren't affected, except
            that they are immutable. That is the key point here:
            the data in the structs does need to be edited though
            There is a 99.8% change this is a mistake [according to the department
            of invented statistics].

            structs in C# (or rather: ValueType in .NET) are not the same as
            structs in C++; they are not a "light weight object" or however else
            people think of them... the difference is the copy vs reference
            semantics. I don't know enough to recommend which... but I firmly
            believe that you'll have a much easier time of things if you either a:
            switch to classes instead of structs, or b: make the structs
            immutable.

            Marc

            Comment

            • Rene

              #7
              Re: ValueType object

              Thanks Mark,



              Nice example for the reason of the "CreateInstance " method existence, very
              cool indeed!




              "Marc Gravell" <marc.gravell@g mail.comwrote in message
              news:ONkuqkHpIH A.4672@TK2MSFTN GP05.phx.gbl...
              Et voila; an "editable" immutable struct via PropertyGrid
              >
              (quoted because it isn't actually an edit; it is a create)
              >
              Marc
              >
              using System.Componen tModel;
              using System.Windows. Forms;
              >
              [TypeConverter(t ypeof(SomeStruc tConverter))]
              public struct SomeStruct
              {
              private readonly int foo;
              private readonly string bar;
              >
              public int Foo { get {return foo;}}
              public string Bar { get {return bar;}}
              >
              public SomeStruct(int foo, string bar)
              {
              this.foo = foo;
              this.bar = bar;
              }
              public override string ToString()
              {
              return string.Format(" {0}:{1}", Foo, Bar);
              }
              }
              >
              sealed class SomeStructConve rter : ExpandableObjec tConverter
              {
              public override bool GetCreateInstan ceSupported(ITy peDescriptorCon text
              context)
              {
              return true;
              }
              public override object CreateInstance( ITypeDescriptor Context context,
              System.Collecti ons.IDictionary propertyValues)
              {
              return new SomeStruct((int )propertyValues["Foo"],
              (string)propert yValues["Bar"]);
              }
              >
              // if you want to be able to edit the text directly
              // rather than via the sub-properties, then you need
              // to implement [Can]ConvertTo / [Can]ConvertFrom looking for
              // string; note that ConvertTo will use ToString by
              // default, so you just need [Can]ConvertFrom
              }
              >
              class SomeType
              {
              private SomeStruct someValue;
              public SomeStruct SomeValue
              {
              get { return someValue; }
              set { someValue = value; }
              }
              }
              >
              static class Program
              {
              static void Main()
              {
              Application.Ena bleVisualStyles ();
              using (Form form = new Form())
              using (PropertyGrid grid = new PropertyGrid())
              {
              grid.Dock = DockStyle.Fill;
              form.Controls.A dd(grid);
              grid.SelectedOb ject = new SomeType();
              Application.Run (form);
              }
              }
              }

              Comment

              • colin

                #8
                Re: ValueType object

                well I agree the struct v class is confusing thing to get used to.
                and the pass by value/ref can be an awkward difference,
                its not always the way you want it to be.

                it would be expensive to replace all structs with classes,
                not only that, the underlying library requires an array of structs for
                various things.
                especially for vertex data wich is itself a struct containing several
                structs,
                and has 200,000 instances.

                although I dont edit this amount of data with the property editor,
                some of the structs are the same type, and this I have little control over,
                or would be too inconvenient to have struct and class duplicated.

                its hard to use TypedReference however, as you cant use it as a field,
                nor can you return it as a function value, you cant even pass it as a ref
                nor cast it to anything not even an object or value type.
                so you have to use it in the same function, or sub function.

                but it does allow you to modify a field of a struct within a struct.
                all you need is an array of FieldInfo wich contain the list of nested
                members,
                and the final fieldinfo, and ofc an object such as a class that holds the
                struct.
                im not sure how it would work on an aray of structs.
                although the class does actually hold a boxed copy of the struct in a
                dictionary.

                //recursively called
                public UData SetField(object value,List<Fiel dInfosubFfields )
                {
                ....
                if(...)
                {
                List<FieldInfof ields = new List<FieldInfo> ();
                parentUdata = parent.SetField (null, fields);
                if (fields.Count 0)
                {
                fields.Reverse( );
                TypedReference typedReference =
                TypedReference. MakeTypedRefere nce(parentUdata .data, fields.ToArray( ));
                fieldInfo.SetVa lueDirect(typed Reference,value );
                return null;
                }
                fieldInfo.SetVa lue(parentUdata .data,value);
                return null;
                }
                ...
                }
                Colin =^.^=

                "Marc Gravell" <marc.gravell@g mail.comwrote in message
                news:e3341d3d-ca33-4bc5-9bbd-f16660a9b310@k1 3g2000hse.googl egroups.com...
                There is no special reason that primatives aren't affected, except
                that they are immutable. That is the key point here:
                >
                >the data in the structs does need to be edited though
                >
                There is a 99.8% change this is a mistake [according to the department
                of invented statistics].
                >
                structs in C# (or rather: ValueType in .NET) are not the same as
                structs in C++; they are not a "light weight object" or however else
                people think of them... the difference is the copy vs reference
                semantics. I don't know enough to recommend which... but I firmly
                believe that you'll have a much easier time of things if you either a:
                switch to classes instead of structs, or b: make the structs
                immutable.
                >
                Marc

                Comment

                Working...