Generic method with objects

Started by
5 comments, last by fafase 11 years, 8 months ago
Hey,

Being not totally advanced yet with C# I am trying to develop a function that would instantiate a list of object.

[source lang="java"]public static List<T> CreateObjLeft<T>(T type) {
List<T> temp = new List<T>();
for (int i = 0; i < 10; i++) {
temp.Add(type); }
return temp;
}[/source]
This is somehow working, I get my 10 objects but I need to access each instance. I created a default constructor for the object, but at the moment all objects in the list have the same attributes and I need to access the position (it is for a game) so that they do not all show on top of each other.

I am trying to create a pattern of object (circle, triangle...) and I would like to be able to use the same generic function for whatever object I want to create (pretty mush the principle of generic methods...).

I have also tried to cast the object inside as such:

[source lang="csharp"]if (type is Asteroid) {
((Asteroid)type).position = new Vector2(0,0);
}[/source]

But then I get an error Cannot convert type T to my own class. Or trying to access the object of the list in the same fashion:


[source lang="csharp"]if (temp is Asteroid) {
((Asteroid)temp)[0].position = new Vector2(0,0);
}[/source]
Error 5 Cannot convert type 'System.Collections.Generic.List<T>' to 'Tutorial.Asteroid'

Does anyone has a solution in mind? Or I thought of trying to add my custom object type to Generic.List<T> but could not really get it...

Thanks
Advertisement
Just to make sure I understood correctly: You want the method to instantiate multiple objects, initialize them all differently and put them in a list?

Assuming that T is a reference type, the first method you provided receives a reference to an object of type T and adds the same reference to the list 10 times. Also, in modern C#, there is really no reason to use the non-generic versions of the built-in collections.


static void Main(string[] args)
{
Action<Asteroid, int, int> initCircle = (obj, i, amount) => {
float a = ((float)i / (float)amount) * MathHelper.TwoPi;
float x = (float)Math.Sin(a);
float y = (float)Math.Cos(a);
obj.position = new Vector2(x, y);
};
var list = CreateMultipleObjects<Asteroid>(10, initCircle);
}
public static List<T> CreateMultipleObjects<T>(int amount, Action<T, int, int> initialize) where T : class, new()
{
List<T> temp = new List<T>();
for (int i = 0; i < amount; i++)
{
T obj = new T();
initialize(obj, i, amount);
temp.Add(obj);
}
return temp;
}

current project: Roa

Thanks a hell of a bunch!!! Unfortunately I can only upvote once...

Well, that did the trick now I need to review all that and understand how and why it works. I have never heard of Action and delegates (still discovering C#).

Also,I was scared you led me somewhere lost as all my object were on the same spot at first but then I realized you just assign the same position in initCircle (I guess you forgot to use i).

Again thanks for that.

Thanks a hell of a bunch!!! Unfortunately I can only upvote once...

Well, that did the trick now I need to review all that and understand how and why it works. I have never heard of Action and delegates (still discovering C#).

Also,I was scared you led me somewhere lost as all my object were on the same spot at first but then I realized you just assign the same position in initCircle (I guess you forgot to use i).

Again thanks for that.


I'm glad I could help smile.png
I used the i in initCircle to calculate a, but you probably have to scale up the vector in order to see the circle.

obj.position = new Vector2(x, y) * 100;

should produce a circle with radius 100.

current project: Roa

One last thing,

[source lang="csharp"]Action<Asteroid, int, int> initCircle = (obj, i, amount) => {
float a = ((float)i / (float)amount) * MathHelper.TwoPi;
float x = (float)Math.Sin(a);
float y = (float)Math.Cos(a);
obj.position = new Vector2(x, y);
};
[/source]
Action<Asteroid, int, int> this declaration will not work if I pass another object type to it, I tried replacing Asteroid with T but no go. The idea would be that if I pass an object of type SpaceShip, it would create s circle of them. Do I need to create a second Action with the SpaceShip or could I alter the existing one so that anything passed would do.

So I can call
[source lang="csharp"]asteroids.AddRange(PatternAst.CreateMultipleObjects<Asteroid>(10, PatternAst.initCircle));
asteroids.AddRange(PatternAst.CreateMultipleObjects<SpaceShip>(10, PatternAst.initCircle));[/source]
(Obvisouly not at the same time) adn I would get a circle of asteroid and a circle of spaceship.

I would guess there is a way to do so.

Sorry for so many questions.
The most straight-forward thing would probably be to make all classes that you want to initialize that way implement a common interface, like "IHasPosition".
Or, if you want to make the your PatternAst class even more generic, you can provide a setter action to the method.


public interface IHasPosition
{
Vector2 Position { get; set; }
}
public class Asteroid : IHasPosition
{
public Vector2 Position { get; set; }
}
public class Asteroid2
{
public Vector2 Position { get; set; }
}
public static class PatternAst
{
static void Main(string[] args)
{
// Use the fact, that Asteroid implements IHasPosition
var list1 = CreateCircle<Asteroid>(10, new Vector2(0, 0), 100);
// Asteroid2 does not implement IHasPosition, use second method with setter action
var list2 = CreateCircle<Asteroid2>(10, new Vector2(0, 0), 100, (obj, pos) => { obj.Position = pos; });
}
private static Vector2 PositionInCircle(int i, int amount, Vector2 center, float radius)
{
float a = ((float)i / (float)amount) * MathHelper.TwoPi;
float x = (float)Math.Sin(a);
float y = (float)Math.Cos(a);
return center + new Vector2(x, y) * radius;
}
public static List<T> CreateCircle<T>(int amount, Vector2 center, float radius) where T : class, IHasPosition, new()
{
var list = CreateMultipleObjects<T>(amount);
for (int i = 0; i < list.Count; i++)
{
list.Position = PositionInCircle(i, list.Count, center, radius);
}
return list;
}
public static List<T> CreateCircle<T>(int amount, Vector2 center, float radius, Action<T, Vector2> positionSetter) where T : class, new()
{
var list = CreateMultipleObjects<T>(amount);
for (int i = 0; i < list.Count; i++)
{
var pos = PositionInCircle(i, list.Count, center, radius);
positionSetter(list, pos);
}
return list;
}
public static List<T> CreateMultipleObjects<T>(int amount) where T : class, new()
{
List<T> temp = new List<T>();
for (int i = 0; i < amount; i++)
{
T obj = new T();
temp.Add(obj);
}
return temp;
}
}

current project: Roa

Actually, either I am wrong or this just got me thinking it was it until I figured out it does not do much more than what I was trying to avoid

In the first place I wanted to have a function that could accept different types of object to do the same action.
What I have now is two functions...That is what I wanted to avoid. Then after reading Action is just a function that does not return any value (but is actually slightly slower than a normal function).


There may be a way around this but at the moment this is actually not doing any thing more than what I was trying to avoid.

This topic is closed to new replies.

Advertisement