开发者

C#: Question about using generics and picking a random type

In my game I'm using a powerup system, which basically works like this:

  • Enemy gets killed, has random chance to drop powerup box
  • Pickup powerup box to get random item

The code for giving the player a random powerup looks like this...

Type t = RandomManager.PickFromParams<Type>(typeof(PowerupInvincible), typ开发者_开发技巧eof(PowerupDoubleFireRate));
ply.AddPowerup<t>();

And the AddPowerup<>() method looks like this:

public void AddPowerup<T>() where T : PowerupEffect, new()
{
    var powerup = new T();

    powerup.Activate(this);
    powerups.Add(powerup);
}

Now, the problem is the ply.AddPowerup<t>() line, because it complains that it can't find the type t:

The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?)

Does anyone know if there's a way to fix this, or if that's not possible, show me a better way to do it? Thanks in advance!


It sounds like you are not using generics correctly in this instance. I'm assuming PowerupInvincible, and PowerupDoubleFireRate inherit from some PowerupBase:

PowerupBase powerUp = RandomManager.PickFromParams<PowerupBase>(typeof(PowerupInvincible), typeof(PowerupDoubleFireRate));

ply.AddPowerup(powerUp);

Then the method signature simple need to be:

public void AddPowerup(PowerupBase powerup)
{
    powerup.Activate(this);
    powerups.Add(powerup);
}

Your random manager would be responsible for choosing one of the parameters, instantiating it, and then returning the instance.


Generics are compile type. t is the type at runtime. You will have to invoke the method using reflection or.

http://blogs.microsoft.co.il/blogs/gilf/archive/2008/10/10/invoking-generic-methods-with-reflection.aspx


you can do something like

public void AddPowerup(Type powerupType) { 
    if (!powerupType.IsSubclassOf(typeof(PowerupEffect)))
       throw some exception here;
    var powerup = Activator.Create(powerupType);
    ....
}


you can fix it - but only with reflection - you have to find the MethodInfo for AddPowerup, make a generic-version from it with type t and then invoke this method for the object ply.


You can't pass Type arguments at runtime, only compile time. So you would need to hard-code the type rather than using t.

You should probably consider using dependency injection, where AddPowerup() does not actually create the new PowerupEffect, but instead takes a PowerupEffect object through a parameter.


The T in <T> should be the real name of a type, not a variable of type Type.


Instantiating generic types is described here:

// Use the typeof operator to create the generic type 
// definition directly. To specify the generic type definition,
// omit the type arguments but retain the comma that separates
// them.
Type d1 = typeof(Dictionary<,>);

// You can also obtain the generic type definition from a
// constructed class. In this case, the constructed class
// is a dictionary of Example objects, with String keys.
Dictionary<string, Example> d2 = new Dictionary<string, Example>();
// Get a Type object that represents the constructed type,
// and from that get the generic type definition. The 
// variables d1 and d4 contain the same type.
Type d3 = d2.GetType();
Type d4 = d3.GetGenericTypeDefinition();

The good thing about reflection, is that you can forgo the need to code a list of implementors:

// TODO proper caching
// TODO proper random generation

var randomType = Assembly.GetAssembly(typeof(MainClass))
    .GetTypes()
    .Where(t => typeof(B).IsAssignableFrom(t))
    .Where(t => !(t.IsAbstract || t.IsInterface))
    .Except(new [] { typeof(PowerupBase) })
    .OrderBy (t => new Random(DateTime.Now.Millisecond).Next())
    .First();

Activator.CreateInstance(x);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜