0

How to create a List variable that can contain array of int or string in C#?

I have a class:

public class GoogleAdSlot
    {
        public IList<int[]> Size { get; set; }
    }

How do I create a List such that

return new GoogleAdData
            {
                AdSlots = new Dictionary<string, GoogleAdSlot>
                {
                    {
                       "googleAdSquareTile1",
                        new GoogleAdSlot {
                           Size = new List<int[]>
                           {
                             new[] {250, 250},
                             new[] {300, 300},
                           }
                       }
                    }
                }
        };

And:

return new GoogleAdData
            {
                AdSlots = new Dictionary<string, GoogleAdSlot>
                {
                    {
                       "googleAdSquareTile1",
                        new GoogleAdSlot {
                           Size = new List<int[]>
                           {
                             new[] {fluid},
                           }
                       }
                    }
                }
        };

are both valid.

8
  • 5
    List<object> maybe, depends why you need this. likely its the wrong apprach Commented Feb 10, 2020 at 3:48
  • What is the type of fluid? Based on the question I'd guess string, yet you're trying to add it to a List<int[]>. Commented Feb 10, 2020 at 4:01
  • What are you going to do with your lists that contain either ints or strings. When you enumerate them, the only variable that can receive them must be typed object. Can a single AdSlot instance contain a mix of strings and ints, or will have only ints or only strings? If the latter. Make the type generic (though you can't constrain things to only those types). If the former, but a single list can contain only a single type, then create a class that represents a collection that is both int-ish and string-ish, allowing both int and string enumeration. Commented Feb 10, 2020 at 4:03
  • Yes the List can contain array of int and the value fluid 'string' or both Commented Feb 10, 2020 at 5:00
  • So, it can either a list of int, or exactly one string: "fluid". Simple create a type that has a bool property like IsListOfInt. Have a private (possibly empty) list of int, and a public enumerator. You don't even need to store the "fluid" string, the absence of the list makes it appear to be there Commented Feb 10, 2020 at 5:51

3 Answers 3

1

sample here

List<object> lst = new List<object>() {  "12",1,"apple"};
lst.ForEach(m => { Console.WriteLine((m is int) ? "int Varible" : "String Varibale"); });
Sign up to request clarification or add additional context in comments.

Comments

1

You can only store one Type and its derived types in a generic List, in the case you described you would have to use List<object> or it's non generic counterpart ArrayList, but non-generic collections are not recommended and don't support newer features like LINQ.

So that would look something like:

var list = new List<object> {"lol", 101};

foreach (var value in list)
{
    if(value is string s)
        Console.WriteLine(s);
    if (value is int i)
        Console.WriteLine(i);
}

2 Comments

"You can only store one Type in a generic List" isn't exactly true. You can store multiple types if they have common ancestry (and, of course, there's always object). I'd say var list = new List<FileSystemInfo>() { new DirectoryInfo(@"C:\"), new FileInfo(@"C:\pagefile.sys") }; contains multiple types. Whether the List<>'s type parameter provides a rich enough interface for its items to be useful without checking their type and casting is another matter. Also, unless you're dealing with legacy code, I don't think there's any reason to use ArrayList, even instead of List<object>.
@BACON thanks for the correction. I adjusted my answer.
0

I'm still not sure exactly what your requirements are, but here's a solution for the most general case.

First

Create a class capable of holding a collection of either integers or strings (but not both). Note that it uses the Collection initialization pattern (twice) (see https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers)

Note that the various GetEnumerator implementations are there only to satisfy the collection initialization pattern. They throw if called, the expectation is that a consumer would call GetIntegerSizes or GetStringSizes.

Here's the code:

public class AdSlotSizes : IEnumerable<int>, IEnumerable<string>
{
    public enum CollectionType
    {
        Uninitialized,
        Integers,
        Strings,
    }

    private List<int> _integerSizes;
    private List<string> _stringSizes;

    public void Add(int sizeToAdd)
    {
        InitializeList(CollectionType.Integers);
        _integerSizes.Add(sizeToAdd);
    }

    public void Add(string sizeToAdd)
    {
        InitializeList(CollectionType.Strings);
        _stringSizes.Add(sizeToAdd);
    }

    public CollectionType SizesCollectionType => _collectionType;

    private CollectionType _collectionType = CollectionType.Uninitialized;

    private void InitializeList(CollectionType forCollectionType)
    {
        CollectionType oppositeCollectionType = (CollectionType)(((int) CollectionType.Strings + 1) - (int) forCollectionType);
        if (_collectionType == oppositeCollectionType)
        {
            throw new ArgumentException($"A single {nameof(AdSlotSizes)} instance can only hold one type of sizes (int or string)");
        }

        if (_collectionType != CollectionType.Uninitialized)
        {
            return;
        }
        _collectionType = forCollectionType;

        if (forCollectionType == CollectionType.Strings)
        {
            _stringSizes = _stringSizes ?? new List<string>();
        }
        if (forCollectionType == CollectionType.Integers)
        {
            _integerSizes = _integerSizes ?? new List<int>();
        }
    }

    public IEnumerable<int> GetIntegerSizes()
    {
        if (_collectionType != CollectionType.Integers)
        {
            throw new ArgumentException("Size collection not initialized for integers");
        }

        foreach (var size in _integerSizes)
        {
            yield return size;
        }
    }

    public IEnumerable<string> GetStringSizes()
    {
        if (_collectionType != CollectionType.Strings)
        {
            throw new ArgumentException("Size collection not initialized for strings");
        }

        foreach (var size in _stringSizes)
        {
            yield return size;
        }
    }

    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

}

Second

Now I create a class that collections AdSlotSizes instances (again, using the collection initialization pattern). It also implements an indexed property (public AdSlotSizes this[int index]), allowing the consumer to index into the collection:

public class GoogleAddSlot : IEnumerable<AdSlotSizes>
{
    private readonly List<AdSlotSizes> _slotSizes = new List<AdSlotSizes>();

    public void Add(AdSlotSizes sizes)
    {
        _slotSizes.Add(sizes);
    }

    public AdSlotSizes this[int index] => _slotSizes[index];

    public IEnumerator<AdSlotSizes> GetEnumerator()
    {
        foreach (var sizes in _slotSizes)
        {
            yield return sizes;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return (IEnumerator < AdSlotSizes > )this.GetEnumerator();
    }
}

Finally, a test method:

public static void TestCollectionSizes()
{
    var slot = new GoogleAddSlot
    {
        {new AdSlotSizes {200, 300, 400} },
        {new AdSlotSizes {"fluid", "solid"}},
    };

    foreach (int size in slot[0].GetIntegerSizes())
    {
        Debug.WriteLine($"Integer Size: {size}");
    }

    foreach (string size in slot[1].GetStringSizes())
    {
        Debug.WriteLine($"String Size: {size}");
    }
}

When run, this test method outputs:

Integer Size: 200
Integer Size: 300
Integer Size: 400
String Size: fluid
String Size: solid

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.