List of generics List<myObject<T>>, is this possible with the Tpossibly changing?

L

lpinho

Hi all,

I have a class (named for the example myObject) that can be of
several types (int, string, float, etc), instead of using a object to
define it's type I used a generic.

public class MyObject<T> : ChangeObject
{
...
public MyObject(string name, T value)
{
// invoke the properties, since there's additional work to
do
Name = name;
Value = value;
}

}

Until now, everything is ok, what I want to do now, is to set a
property inside a class that is a list of these objects.
So I thought it would be has easy has:

List<MyObject<T>> Objects;

or even:

MyObject<T>[] Objects;

But it seems that the T only works on class definitions, is this
true?
What can I do to have a list of generic objects of this kind?

Thanks
 
M

Marc Gravell

The "T" is defined for the entirety of the generic type or generic
method that declares it. So any code inside MyObject<T> can make use of
T. However, code outside of MyObject<T> has no idea *which* T you are
talking about.

In your regular C# code, you must indicate what you are talking about -
for example you might have a "List<MyObject<Foo>> objects".
Alternatively, if you are inside a generic type/method, you can use your
local generic arguments instead:

public void Bar<TSomethingElse>() {
List<MyObject<TSomethingElse>> objects = ...
}

(TSomethingElse here named to distinguish that this is a *different*
generic type-argument to the T in MyObject<T>).

Constraints and type-inference can greatly simplify this - but it is
hard to show a meaningful example without more context as to what
exactly you want to do.

Marc
 
L

lpinho

The "T" is defined for the entirety of the generic type or generic
method that declares it. So any code inside MyObject<T> can make use of
T. However, code outside of MyObject<T> has no idea *which* T you are
talking about.

In your regular C# code, you must indicate what you are talking about -
for example you might have a "List<MyObject<Foo>> objects".
Alternatively, if you are inside a generic type/method, you can use your
local generic arguments instead:

public void Bar<TSomethingElse>() {
List<MyObject<TSomethingElse>> objects = ...

}

(TSomethingElse here named to distinguish that this is a *different*
generic type-argument to the T in MyObject<T>).

Constraints and type-inference can greatly simplify this - but it is
hard to show a meaningful example without more context as to what
exactly you want to do.

Marc

The "T" is defined for the entirety of the generic type or generic
method that declares it. So any code inside MyObject<T> can make use of
T. However, code outside of MyObject<T> has no idea *which* T you are
talking about.

In your regular C# code, you must indicate what you are talking about -
for example you might have a "List<MyObject<Foo>> objects".
Alternatively, if you are inside a generic type/method, you can use your
local generic arguments instead:

public void Bar<TSomethingElse>() {
List<MyObject<TSomethingElse>> objects = ...

}

(TSomethingElse here named to distinguish that this is a *different*
generic type-argument to the T in MyObject<T>).

Constraints and type-inference can greatly simplify this - but it is
hard to show a meaningful example without more context as to what
exactly you want to do.

Marc

Hi Marc,

thanks for your reply.

I will try to give you my concrete example:
We have several objects that can have a set of user attributes
(defined by the user), these attributes can be of several types (int,
string, float, etc), so, we defined a UserDefinedAttribute class:

public class UserDefinedAttribute<T>
{
[XmlElement("Value")]
public T Value
{
get {
return this.value;
}

set {
// Make sure the type information is not violated
validateType(value);

this.value = value;

// Infer type and size information if unknown
inferType();
}
}

private void inferType()
{
if (this.dataType == (sbyte)Globals.DataTypesEnum.Unknown)
{
Type type = typeof(T);
if (type.IsArray)
{
this.size = (this.value as Array).Length;
}

if (type == typeof(int) || type == typeof(int []))
{
this.dataType =
(sbyte)Globals.DataTypesEnum.Integer;
}
else if (type == typeof(bool) || type ==
typeof(bool[]))
{
this.dataType =
(sbyte)Globals.DataTypesEnum.Boolean;
}
else if (type == typeof(string) || type ==
typeof(string[]))
{
this.dataType =
(sbyte)Globals.DataTypesEnum.String;
}
else if (type == typeof(float) || type ==
typeof(float[]))
{
this.dataType =
(sbyte)Globals.DataTypesEnum.Float;
}
else
{
}
}
}

public UserDefinedAttribute(string name, T value)
{
// invoke the properties, since there's additional work
todo
Name = name;
Value = value;
}
}


So, the attributes are defined.

Now I have other classes like Auto that must have a list of
UserDefinedAttribute, the original developer used an array list for
this, but I would like to have something like
List<UserDefinedAttribute<T>>, but the framework doesn't let me.
I know that I can have List<UserDefinedAttribute<string>> or
List<UserDefinedAttribute<int>>, but since the type may vary from
UserDefinedAttribute to UserDefinedAttribute I would like to have a
generic type.

Can you point me in the right direction?

Thanks
 
M

Marc Gravell

Right; in this case, I might have a non-generic interface to use -
soemthing like IUserDefinedType below. Then you can have a list of
IUserDefinedType. That is the probably closest you can get if the T can
change per item in the list.

Note also that there are other ways of modelling flexible properties -
for example, if you use data-binding, System.ComponentModel allows you
to have runtime properties via ICustomTypeDescriptor or
TypeDescriptionProvider. Quite an involved area, but if you make use of
data-binding, let me know - I can give you some hints to get this working...

Marc

public interface IUserDefinedType
{
object Value { get; set; }
Type Type { get; }
}
public interface IUserDefinedType<T> : IUserDefinedType
{
new T Value { get; set; }
}
public class UserDefinedType<T> : IUserDefinedType<T>
{
public T Value { get; set; }
public Type Type { get { return typeof(T); } } // or whatever
object IUserDefinedType.Value
{
get { return Value; }
set { Value = (T)value; }
}
}
 
G

Göran Andersson

lpinho said:
Now I have other classes like Auto that must have a list of
UserDefinedAttribute, the original developer used an array list for
this, but I would like to have something like
List<UserDefinedAttribute<T>>, but the framework doesn't let me.
I know that I can have List<UserDefinedAttribute<string>> or
List<UserDefinedAttribute<int>>, but since the type may vary from
UserDefinedAttribute to UserDefinedAttribute I would like to have a
generic type.

You can't declare any other type than List<Object> that can hold both
UserDefinedAttribute<string> and UserDefinedAttribute<int>, as Object is
the only common base class for those types.

You can make a non-generic interface:

interface IUserDefinedAttribute {}

Let the UserDefinedAttribute class implement this interface, then you
can declare a list of attributes:

List<IUserDefinedAttribute>

This of course doesn't do much unless you put some method signatures in
the interface, but at least you are able to declare a list that can only
contain attributes.
 
M

Marc Gravell

(I meant IUserDefinedAttribute, btw, not IUserDefinedType; head on
sdrawkcab today...)
 
B

Ben Voigt [C++ MVP]

lpinho said:
Hi all,

I have a class (named for the example myObject) that can be of
several types (int, string, float, etc), instead of using a object to
define it's type I used a generic.

public class MyObject<T> : ChangeObject
{
...
public MyObject(string name, T value)
{
// invoke the properties, since there's additional work to
do
Name = name;
Value = value;
}

}

Until now, everything is ok, what I want to do now, is to set a
property inside a class that is a list of these objects.
So I thought it would be has easy has:

List<MyObject<T>> Objects;

or even:

MyObject<T>[] Objects;

But it seems that the T only works on class definitions, is this
true?
What can I do to have a list of generic objects of this kind?
 
L

lpinho

Hi Again Marc,

sorry to bother you again, I seemed to block in another point, I did
has you suggested and it worked very well.

Now I'm facing another problem, serialization :(

This is what I've done:

[XmlArray("UserDefinedAttributes")]
[XmlArrayItem("UserDefinedAttribute")]
public ArrayList XmlAttributes
{
get {
ArrayList output = new ArrayList();
if (attributes != null)
{
foreach (IUserDefinedAttributes
tmpUserDefinedAttributes in this.attributes)
{
Type typeOfUDA = tmpUDA.Type;
if (typeOfUDA == typeof(string))

output.Add((UserDefinedAttribute<string>)tmpUDA);
else if (typeOfUDA == typeof(int))

output.Add((UserDefinedAttribute<int>)tmpUDA);
else if (typeOfUDA == typeof(float))

output.Add((UserDefinedAttribute<float>)tmpUDA);
else if (typeOfUDA == typeof(DateTime))

output.Add((UserDefinedAttribute<DateTime>)tmpUDA);
else if (typeOfUDA == typeof(TimeSpan))

output.Add((UserDefinedAttribute<TimeSpan>)tmpUDA);
else if (typeOfUDA == typeof(bool))

output.Add((UserDefinedAttribute<bool>)tmpUDA);
else
output.Add((UDA<object>)tmpUDA);
}
}
return output;
}
set {
ArrayList input = value;
this.attributes = new List<IUserDefinedAttribute>();
foreach (IUserDefinedAttribute tmpUDA in input)
{
attributes.Add(tmpUDA);
}
}
}

[XmlIgnore]
public List<IUserDefinedAttribute> Attributes
{
get {return this.attributes;
}
set { this.attributes = value; }
}

It seems that a list of interfaces would not work since it seems that
only "real" classes can be serialized, so I created an array list,
catch the type and the serialization seems to work correctly, the
problems appear when the deserialization occur, for some reason, it
seems that the deserialization for this property doesn't occur, and
unfortunately, if I try to set the type of the ArrayItem
(IUserDefinedAttribute) it will not work because IUserDefinedAttribute
is an interface.

Is it possible to overcome this? (If I set a breakpoint on the set
method, it not even being called)
 
M

Marc Gravell

Not really; you'd need to be able to specify the actual type to
instantiate in the XmlArrayItemAttribute - which you simply can't in
this case. You could perhaps use custom serialization
(IXmlSerializable), but it isn't (necessarily) easy...

Marc
 
L

lpinho

Not really; you'd need to be able to specify the actual type to
instantiate in the XmlArrayItemAttribute - which you simply can't in
this case. You could perhaps use custom serialization
(IXmlSerializable), but it isn't (necessarily) easy...

Marc

OK :(

Thanks
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top