0

Lets say I have a struct with more than hundred elements with complex names. And I am passing a struct of the struct type described to a function using ref, like this:

void Foo(ref mystruct a)
{
   "I want to modify members or fields of struct a, like this:
   a[0] = 10;
   a[100] = 11;"
}

Thanks!

8
  • 1
    Why would you want to have a struct with 100 fields? Commented Jul 19, 2011 at 16:03
  • 1
    You could use reflection to ascertain the entries, but do not do this. It is wrong. @Yossarian is right. Commented Jul 19, 2011 at 16:03
  • 4
    A: mutable structs are evil B: structs should be sensibly sized (ref is a hacky workaround). Unless you have a very specialised scenario, this isn't a great way to design it... Commented Jul 19, 2011 at 16:04
  • its not 100, its exactly 26. I'm just making it up to show that the Struct has many fields. Commented Jul 19, 2011 at 16:05
  • 3
    I'm pretty sure this is a port of some legacy C code (as your other question was.) Part of porting is realizing when something was done in a poor way and fixing it. In this case, an array makes much more sense than keeping the struct around. As SLaks recommended in the previous question, wrap the array in a class with appropriate property getters/setters if you feel the need. Commented Jul 19, 2011 at 16:05

5 Answers 5

3

Maybe you should re-examine your choice of data structure. Perhaps a dictionary would be better suited?

Sign up to request clarification or add additional context in comments.

Comments

2

It's a strange request as you're expecting the order of the fields to be significant, but I suspect you could do this through Reflection or the TypeDescriptor.

I would revise my code sample below to use proper property names with constants, but if you know the property names, just call the properties directly and save yourself from the reflection overhead. Otherwise, use a dictionary with constants.

/* yeah, probably not a good idea.
public void Foo(ref MyStruct a)
{
    TypeDescriptor.GetProperties(a)[0].SetValue(a, 10);
}
*/

3 Comments

Properties are explicitly not reported in any defined order. MSDN is clear about this.
Thanks Marc, and the link to support this: msdn.microsoft.com/en-us/library/aky14axb.aspx
wth? people are down voting my updated copy that recognizes this as a bad idea? thanks guys, you are all scholars.
1

While you can use the struct LayoutKind attribute to force simple types to share memory like a "C" Union, you still cannot make an array share memory with simple types because ref types (aka garbage collected types) don't work with the attribute. The concept of C shortcuts like memset of a struct don't map to C# in any way, because C# is a safe language. In fact, that is a Good Thing. Many bugs have come from these kinds of memory addressing shortcuts.

If you want to simulate this behavior, create a class with properties that map to specific members of a backing array, but again, why do this? There are much better data structures to suit your needs in C# such as List, SortedList, Dictionary, Map, Stack, etc. that are safe.

Comments

0

You can do this in .NET BUT as several others have already posted: DO NOT DO IT.

Some Code

a.GetType().GetProperties() [0].SetValue (a, newvalue, null);

EDIT: several reasons not to do this:

  • the order is not guaranteed !

  • what happens when there are no properties ?

  • what happens with readonly properties ?

So again: DO NOT DO THIS!

3 Comments

As has been pointed out, you cannot guarantee what order properties are returned in when using reflection, so you cannot use ordinals.
In case you didn't read the first line - I wrote "DO NOT DO IT". I added some explanation to my answer...
I did read the first line, it didn't say why not to to do it, plus someone answered with exactly the same answer 22 minutes before you...
0

I will probably burn in hell, but...

Obviously horrible and not recommended and only works if your fields are all ints with default layout...

internal class Program
{
    private struct MyStruct
    {
        //Must be all Int32
        public int Field1, Field2, Field3;
    }

    private static void Main()
    {
        MyStruct str = new MyStruct {Field1 = 666, Field2 = 667, Field3 = 668};

        int[] array = ToArray(str);

        array[0] = 100;
        array[1] = 200;
        array[2] = 300;

        str = FromArray(array);
    }

    private static int[] ToArray(MyStruct str)
    {
        IntPtr ptr = IntPtr.Zero;

        try
        {
            int size = GetInt32ArraySize(str);
            int[] array = new int[size];
            ptr = Marshal.AllocHGlobal(size);
            Marshal.StructureToPtr(str, ptr, true);
            Marshal.Copy(ptr, array, 0, size);
            return array;
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }
    }

    private static MyStruct FromArray(int[] arr)
    {
        IntPtr ptr = IntPtr.Zero;

        try
        {
            MyStruct str = new MyStruct();
            int size = GetInt32ArraySize(str);
            ptr = Marshal.AllocHGlobal(size);
            Marshal.Copy(arr, 0, ptr, size);
            str = (MyStruct)Marshal.PtrToStructure(ptr, str.GetType());
            return str;
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }
    }

    private static int GetInt32ArraySize(MyStruct str)
    {
        return Marshal.SizeOf(str) / Marshal.SizeOf(typeof(Int32));
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.