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'
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With