Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare an array containing generic type?

Tags:

c#

generics

Say I have the following type:

public class Field<T>
{
  public string Name { get; set; }
  public T Value { get; set; }
}

How can I declare a variable that will contain an array of such Fields? I tried the following:

var customFields = new Field[]
{
    new Field<string> { Name = "nickname", Value = "Bob" },
    new Field<int> { Name = "age", Value = 42 },
    new Field<DateTime> { Name = "customer_since", Value = new DateTime(2000, 12, 1) }
};

but I get the following compile-time exception:

Using the generic type 'Field' requires 1 type arguments

I also tried var customFields = new Field<object>[] but I get the following errors:

Cannot implicitly convert type 'Field' to 'Field'

Cannot implicitly convert type 'Field' to 'Field'

Cannot implicitly convert type 'Field' to 'Field'

like image 963
desautelsj Avatar asked Oct 21 '16 15:10

desautelsj


People also ask

Can you create an array of generic type?

Java allows generic classes, methods, etc. that can be declared independent of types. However, Java does not allow the array to be generic. The reason for this is that in Java, arrays contain information related to their components and this information is used to allocate memory at runtime.

How do you declare an array as generic in Java?

The first parameter specifies the type of object inside the new array. The second parameter specifies how much space to create for the array. As the result of Array#newInstance is of type Object, we need to cast it to E[] to create our generic array.

Can generics be applied to arrays?

You will find that a simple statement like this will not even compile because the Java compiler does not allow this. To understand the reason, you first need to know two arrays are covariant and generics are invariant. Because of this fundamental reason, arrays and generics do not fit well with each other.


2 Answers

As Matias said it can't be done that way because Field<int> and Field<string> are completely different types. What you can do is:

Create a base Field which is not generic:

public class Field
{
    public string Name { get; set; }
}

public class Field<T> : Field
{
    public T Value { get; set; }
}

And then:

var customFields = new Field[]
{
    new Field<string> { Name = "nickname", Value = "Bob" },
    new Field<int> { Name = "age", Value = 42 },
    new Field<DateTime> { Name = "customer_since", Value = new DateTime(2000, 12, 1) }
};

As Matias commented a downcasting will be needed to get the Value of the different types. If for each different type of Value there is a specific logic to perform, a nice way to handle it will be to use the Factory design pattern. The factory will return for each Field a correct "FieldHandler<T>" that will downcast, do the operation and return what is needed.

like image 197
Gilad Green Avatar answered Oct 30 '22 23:10

Gilad Green


Another thing you can do is to simply use the common base class for all of those types - Object.

class Field
{
    public string Name { get; set; }
    public Object Value { get; set; }
}
var customFields = new Field[]
{
    new Field { Name = "nickname ", Value = "Bob" },
    new Field { Name = "age", Value = 42 },
    new Field { Name = "customer_since", Value = new DateTime(2000, 12, 1) }
};

However, this would be offloading some type handling to the consumer of customFields, but should be fine if the Value types associated with a specific Field Name are known.

like image 21
Viet Trang Avatar answered Oct 30 '22 23:10

Viet Trang