0

I have a generic method which will accept generic type T. I know that at runtime T will be some type of struct out of a set of structs I have defined previously. I am having trouble figuring out how to instantiate the struct and initialize the fields of the struct.

public void mymethod<T>() {
    // T is a struct which I know will have certain fields. 
    // I want to initialize them in this method
    Type type = typeof(T);
    System.Reflection.MemberInfo attributes = typeof(T);
    //which line is correct, top one or one below?
    //System.Reflection.MemberInfo attributes = typeof(T).GetMember("length", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)[0];
}

Do I need to assign a MemberInfo object for each of the fields I know will be present? Or is it possible to just get all the fields of the passed in struct (since I know different structs will have certain different fields that others dont). Also, once I have a field, how do I assign it a value for that particular struct?

Just to make the problem clearer: what I'm trying to accomplish is the following. I know for sure that during runtime my_method will be accepting some sort of struct from a set of structs I have defined in a different class. Here is an example of 2 of those structs:

public struct Struct1 {
     public int length;
     public int width;
}

public struct Struct2 {
     public int length;
     public int width;
     public int height;
     public string color;
}

mymethod() will accept a generic struct as T. I want to assign fields to that struct based on calculations I do in mymethod (which are irrelevant so I haven't shown them here). Each struct has some basic fields (such as in the example above, both Struct1 and Struct2 have length and width, but Struct2 has more attributes). For whatever struct is passed in as T, I want to assign values to its fields. So for example, if Struct2 is passed in to T, then I want to say

struct2.length = 1;
struct2.width = 2;
struct2.height;
struct2.color;

I need to find the generic equivalent of doing the above, so I tried using MemberInfo to achieve this. My question is how can I assign at least the basic fields of whatever struct is passed in? I know that if I said Struct2 struct2 = new Struct2() then all the attributes are initalized but I can't really say typeof(T) somestruct = new typeof(T) So, do I need to initialize MemberInfo objects for each of the fields that may or not be there? I don't think this will work since different structs will have different fields. It is better if there is a way to get all the fields of a struct, initialize them to some basic value (such as what is done when you say Struct2 struct2 = new Struct2()) and then assign actual values to the fields of the struct I know will be there. How do I assign fields to a generic object?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Jeremy Fisher
  • 2,510
  • 7
  • 30
  • 59
  • I think this question provides your answers: http://stackoverflow.com/questions/2974519/generic-constraints-where-t-struct-and-where-t-class – GinjaNinja Jul 10 '15 at 14:10
  • okay so that will allow me to access all attributes. but now how do I initialize them. For example, I know that in a struct there will be an attribute "length". If I know length is the second attribute defined, can I say "attributes[1] = 1"? – Jeremy Fisher Jul 10 '15 at 14:11
  • It's difficult to see what you're trying to accomplish here, since you haven't told us anything about the actual problem you're trying to solve. You can't "initialize a type," unless you mean instantiate it, or perhaps make an assignment to one of its `static` members. In short, we need to know more about what you're actually trying to accomplish. – Robert Harvey Jul 10 '15 at 14:11
  • http://stackoverflow.com/questions/619767 – Robert Harvey Jul 10 '15 at 14:18
  • I think you're misusing the term "attribute". Attributes specifically inherit from the `Attribute` class and are used for defining object metadata. You don't seem to be doing that here. All it seems like you want to do is set fields. – David L Jul 10 '15 at 14:21
  • you're correct, I edited my question – Jeremy Fisher Jul 10 '15 at 14:24
  • 2
    Please don't call *attributes* what in C# is called **fields**! – Matías Fidemraizer Jul 10 '15 at 14:24
  • @RobertHarvey so would the equivalent be saying typeof(T) instead of "obj" in that example? Also if there are multiple fields to instantiate then will copying that line for each of the fields modify the same struct or invoke different structs? I need to return this struct from mymethod – Jeremy Fisher Jul 10 '15 at 14:31
  • @DavidL yes, I am trying to set fields of a generic type (which I know is some sort of struct) and return the struct. – Jeremy Fisher Jul 10 '15 at 14:33
  • You use generics in very wrong manner. And, moreover, why do you use structs instead of classes? You should use structs if and only if you know what you do and why. Structs can increase speed of some algorithms but if it used wrong, it will slowed your application and increase memory consumption. – Kirill Bestemyanov Jul 10 '15 at 14:39
  • As I suspected, based on your edit, what you probably want to be doing is using Interfaces for this, not Reflection. You should also have a look at `dynamic`. – Robert Harvey Jul 10 '15 at 14:48
  • I'm patching someone else's code, so I'm not going to change everything that's external to this method. Essentially all that the user will be doing is using my method instead of the old method. This should not be this difficult of a problem, all I am trying to do is assign attributes of a generic type. – Jeremy Fisher Jul 10 '15 at 14:48
  • Figure out what type it is using `typeof`, cast it to the correct type and make your assignments in a `switch` statement. No need for reflection. – Robert Harvey Jul 10 '15 at 14:50
  • @RobertHarvey I have tried using dynamic but I ran into a weird issue that no one could solve. I posted a question about it but got no answers other than "you're clearly not posting everything" even though I was. http://stackoverflow.com/questions/31325797/one-or-more-types-required-to-compile-a-dynamic-expression-c-sharp – Jeremy Fisher Jul 10 '15 at 14:50

1 Answers1

0

The following will iterate over all fields in your original struct and, if present on the new destination struct instance, will map them.

void Main()
{
    var instance = MyMethod<Struct1, Struct2>(new Struct1() { length = 1, width = 2});
}

public TTo MyMethod<TFrom, TTo>(TFrom fromStruct)
{
    var toType = typeof(TTo);
    var instance = Activator.CreateInstance<TTo>(); 

    foreach (var fromField in fromStruct.GetType().GetFields())
    {
        var toField = instance.GetType().GetField(
            fromField.Name, BindingFlags.Public | BindingFlags.Instance);

        if (toField != null)
        {
            var value = fromField.GetValue(fromStruct);
            TypedReference reference = __makeref(instance);
            toField.SetValueDirect(reference, value);
        }
    }

    return instance;
}

Now that said, while this works YOU SHOULD NOT DO THIS! This is mutating a struct via the undocumented __makeref method (thanks to this answer). If you want to copy from one instance to another in this manner, you really should be using be using classes with public properties.

Community
  • 1
  • 1
David L
  • 32,885
  • 8
  • 62
  • 93