Data structures are aptly named, that is, they are simple structures of data. As such, when you pass them around, you're passing around a copy of that data.
So, assuming you have a List<Research> called re, if you go:
re[val].have = true;
While the statement itself is valid, its effect isn't quite what is intended, which is why it's viewed as an error. Since it's always passed around as a copy, and indexing in C# is basically a parameterized property named 'Item' with a single parameter named 'index', when you assign 'have' you're assigning the value 'have' to a copy of the Research data structure that is stored in the list.
The reason for this error is due to the .NET Common Language Infrastructure. All types can be classified into two major categories: Value types and Reference types. Value types, like Enums and Structs, are always passed around by their 'value'. So when you pass a value type (say a struct named Research) via a parameter, if someone changes a value on that value-type instance, the original value remains unchanged. This is because it's simply copied every time you pass it around.
Take the following example:
Research a = new Research();
a.have = true;
Research b = a;
b.have = false;
Console.WriteLine(a.have); //Is still true!
If 'Research' was a class, the value printed to the console would be false, as intended.
This is why assigning a value to a member of an element of a List of Research structs is not valid. You're basically assigning the value to a copy of your intended target; thus, a wasted operation.