1

I'm trying to find a struct I created earlier that has a specific value. Once I found it, I want to set variables on that struct. I don't know how to do this. Is there a better way of doing this? Maybe classes? Or should structs work?

For example, my struct:

public struct MyTest
{
    public string device;
    public string status;
    public string revision;
    public string number;
    public string ledmo;        
}

My Test Code:

MyTest thisTest=new MyTest();
thisTest.device=blah;
thisTest.number=blah2;

MyTest thisTest2=new MyTest();
thisTest2.device=blah5;
thisTest2.number=blah6;

//Another Part in my code.
//Need to find the MyTest Structure that 'device' variable = the string 'blah'
var Foundit=MyTest.find(device==blah);
Foundit.revision=blah9999;
user1147223
  • 88
  • 1
  • 7

4 Answers4

2

To be able to find instances of an object created earlier, these instances need to be saved somewhere.
One solution would be to put them into a list and later search that list:

var list = new List<MyTest>();

MyTest thisTest=new MyTest();
thisTest.device=blah;
thisTest.number=blah2;
list.Add(thisTest);

MyTest thisTest2=new MyTest();
thisTest2.device=blah5;
thisTest2.number=blah6;
list.Add(thisTest2);

Now you can search using LINQ:

var foundItems = list.Where(x => x.device == "blah");
foreach(var foundItem in foundItems)
{
    foundItem.revision = "blah9999";
}

Please note:
This only works when you use classes instead of structs as Binary Worrier points out in his comment.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • -1: Sorry, but this won't work. Because value types are copied on assignment (or when passed to functions), the list holds **copies** of `thisTest` and `thisTest2`. Therefore `foundItem` is a **copy** of `thistest` (actually it's at least a copy of a copy, if not a copy of a copy of a copy), and when you change the revision with `foundItem.revision = "blah9999";` you are changing the copy, `thisTest` remains unchanged. – Binary Worrier Jan 13 '12 at 08:55
2

I'd use a class, because Mutable structs are evil

Basically, because every struct is copied, even if you do find the right struct, you'll only ever change one copy. Lets say MyTest.find finds thisTest2 what happens is this

var Foundit = MyTest.Find(device==blah); 
// The line above has made a copy of thisTest2, that copy is in FoundIt

Foundit.revision = "blah9999";
// You've changed revision in the copy of thisTest2, 
// therefore the contents of thisTest2 remain unchanged

To do this with a class you'll need to keep every instance of the class you create in a list or other data structure, so you know you can look it up.

If you do this you also need to tell the list when you're finished with each object, otherwise they'll hang around forever and never get garbage collected.

Before I go any further, are you sure this is the best way to solve this problem?

Anyway, say your class is MyData, you can put a static factory method on this called Create, which will put each new MyData object into a list.

public class MyData
{
    private static List<MyData> allMyDatas = new List<MyData>();
    public static IEnumerable<MyData> AllInstances
    {
        get {return allMyDatas;}
    }

    public string Device {get; set;}
    public string Status {get; set;}
    public string Revision {get; set;}
    public string Number {get; set;}
    public string Ledmo {get; set;}

    private MyData() // Private ctor ensures only a member 
    {                // function can create a new MyData
    }
    public static MyData Create()
    {
        var newData = new MyData();
        allMyDatas.Add(newData);
        return newData;
    }

    public static void Delete(MyData itemToRemove)
    {
        allMyDatas.Remove(itemToRemove);
    }
}

Everywhere you use a MyData you'll need to Delete it when you're finished with it.

Your code becomes

var thisTest = MyData.Create();
thisTest.Device = "blah";
thisTest.Number = "blah2";

var  thisTest2 = MyData.Create();
thisTest2.Device = "blah5";
thisTest2.Number = "blah6";

//Another Part in my code.
//Need to find the MyData Structure that 'device' variable = the string 'blah'
var Foundit = MyData.AllInstances.FirstOrDefault(md => md.Device == "blah");
if(Foundit != null)
    Foundit.Revision = "blah9999";    

Changing FoundIt now also changes thisTest

P.S.: It's important that nothing outside MyData can new an instance of MyData. If it could, then there would be an instance of MyData that you couldn't find in AllInstances. Declaring the constructor private means a compiler error will be generated if code outside MyData tries something like var someData = new MyData

Community
  • 1
  • 1
Binary Worrier
  • 50,774
  • 20
  • 136
  • 184
  • Code has been compiled, test and fixed. – Binary Worrier Jan 13 '12 at 09:06
  • I've started saying that mutable structs aren't evil, they're just misunderstood. Of course, misunderstood is actually worse than evil when it comes to programming :) – Jon Hanna Jan 13 '12 at 10:33
  • Hi. Just a quick followup. This method of going about this worked. But earlier you asked if I thought this was the best method of going about the issue here. What would you have done differently? I'm open to new ideas, it's just the only idea I know. – user1147223 Jan 25 '12 at 01:12
  • @user1147223: Without knowing exactly why you need to do this, I can't tell you what a better way might be. It just strikes me as an odd way to solve a problem. What you could do is describe what your program does, and how you use this cache of obects & why you need to find random ones. Put it in a new question and ask "I suspect there may be a better way of doing this, can you help", and post a link to the new question in a comment on this answer and I'll take a look. I'm glad I could help. – Binary Worrier Jan 25 '12 at 07:48
0

You can use lists and Linq for that.

var test = new List<MyTest>();
//Add some items
var foundIt = test.SingleOrDefault(test => test.device == "abc");//Maximum one
if(foundIt != null)//Use a class for MyTest.
   foundIt.device = "123"
Carra
  • 17,808
  • 7
  • 62
  • 75
  • Sorry but this won't work. `SingleOrDefault` will return a **copy** of the struct into `foundIt`, therefore `foundIt.device = "123"` is changing the copy and the original remains unchanged. – Binary Worrier Jan 13 '12 at 08:51
0

In this case a class would work better because of the dynamic string size and the fact that there are so many strings.

With your test code, you should be storing a List<MyTest> somewhere in that class and adding thisTest and thisTest2 to the list. You can later retrieve specific values (or all the values of a certain device) with the FindAll or similar methods.

List<MyTest> list = new List<MyTest>();
//add MyTests here...

var foundIt = list.FindAll(x => x.device == "blah");
Robert Rouhani
  • 14,512
  • 6
  • 44
  • 59
  • Can you elaborate on your first sentence? I can't see how that makes sense in its current form. – Daniel Hilgarth Jan 13 '12 at 08:19
  • 1
    In this case structs are much slower than classes given how much data it will be storing (and the fact that the size can't be determined at compile-time). Microsoft recommends [a maximum of 16 bytes for structs](http://msdn.microsoft.com/en-us/library/ah19swz4(v=vs.71).aspx). After that the expected speed benefit of being a `ValueType` actually becomes [a bottleneck](http://stackoverflow.com/questions/2407691/c-struct-design-why-16-byte-is-recommended-size). – Robert Rouhani Jan 13 '12 at 08:27
  • 1
    Robert Rouhani: The struct will store references to the strings, but will not store the contents of the strings e.g. `myTest.Device = "Hello"; myTest2.Device = myTest.Device;` both `myTest` and `myTest2` store a referece to the string "Hello", there is only one string object here. Ergo the compiler does know the struct size at compile time. – Binary Worrier Jan 13 '12 at 08:45
  • Hmm, for some reason I momentarily thought that strings were allocated on the stack, I'm not really sure why... probably a lack of sleep. Either way it's still 20 bytes on a 32-bit system and 40 bytes on a 64-bit system, which would make the struct slower (but probably not significantly) – Robert Rouhani Jan 13 '12 at 08:56