简体   繁体   中英

C#: How to access structs in ArrayList?

It's probable the question of typization (in C++ with STL everything would be made through std::vector and no questions would appear).

I have an ArrayList and I'd like to store some structs there. Like

    struct txtRange
    {
        public String sText;
        public String sTag;
        public int iBeg;
        public int iEnd;
    };

    ArrayList Ranges = new ArrayList();   

    txtRange iRange;
    iRange.sText = entityText;
    iRange.sTag = "";
    iRange.iBeg = Ranges.Count > 0 ? Ranges[Ranges.Count - 1].iEnd + 1 : 0;
    iRange.iEnd = iRange.iBeg + tmpstr.Length;
    Ranges.Add(iRange);

Actually, I have troubles when accessing Ranges[Ranges.Count - 1].iEnd: 'object' does not contain a definition for 'iEnd'. How should a ArrayList of the type specified be created?

The similar question ( How to cast object/structure into arraylist? ) made me laugh a bit... But still, there is an explanation how to add structures into ArrayList but not how to get the values from there.

You have three problems here:

  1. You're using mutable structs. That's a bad idea to start with. Why isn't txtRange a class?

  2. You're using public fields - no encapsulation.

  3. You're using the non-generic ArrayList type which means everything is getting boxed and you only have weak typing.

You can cast the result as you remove it, but then if you want to change the contents, you'll have to put it back again (because it's a struct, and is being copied each time). The snippet you've given doesn't actually need to change anything, but you're likely to run into it at some point. Here's the snippet in working code:

txtRange iRange;
iRange.sText = entityText;
iRange.sTag = "";
iRange.iBeg = Ranges.Count > 0 ? ((txtRange) Ranges[Ranges.Count - 1]).iEnd + 1 
                               : 0;
iRange.iEnd = iRange.iBeg + tmpstr.Length;
Ranges.Add(iRange);

However, I would suggest:

  • Rename txtRange to TextRange
  • Use a generic List<T> instead of ArrayList unless somehow you're working on a platform which doesn't support generics (the microframework or .NET 1.1)
  • Either make TextRange immutable, or make it a class - or possibly both
  • Use properties instead of public fields (see here for more reasons)
  • Avoid using abbreviations, and I would personally ditch the "i" prefix (I'd use Start, Tag, End, Text)

As I see it, you just need to cast the output.

((txtRange)Ranges[Ranges.Count-1]).iEnd 

Or use List<txtRange> instead for strongly typed loving.

You need to first cast it to a type of txtRange before you can access its propertys the way you specified.

Or you can always go the List<T> where t is txtRange route as that will work without casting

iRange.iBeg = Ranges.Count > 0 ? ((txtRange)Ranges[Ranges.Count - 1]).iEnd + 1 : 0;

Thanks, the problem can both be solved by an explicit cast like

 iRange.iBeg = Ranges.Count > 0 ? ((txtRange)Ranges[Ranges.Count - 1]).iEnd + 1 : 0;

or by using generics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM