2016-03-01 3 views
1

У меня есть этот класс, чтобы генерировать случайные объекты:Изменение общего типа из класса

public class Generator<T> 
{ 
    private Random rnd = new Random(); 
    private List<Type> types = new List<Type>(); 

    public Generator() 
    { 
     //can't a generic type constraint that says "implements any interface" so I use this ugly thing... 
     if (!typeof(T).IsInterface) 
      throw new Exception("Generator needs to be instanciated with an interface generic parameter"); 

     types = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(T))).ToList(); 
    } 

    public T GetRandomObject() 
    { 
     int index = rnd.Next(types.Count); 
     return (T)Activator.CreateInstance(types[index]); 

    } 

    public void SetNewGeneric<N>() 
    { 
     T = N; //this doesn't work... 
     types = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(T))).ToList(); 
    } 

} 

Я использую его так:

Generator<IEnemy> generator = new Generator<IEnemy>(); 
var randomEnemy = generator.GetRandomObject(); //create and return randomly, any object that implements IEnemy... 

мой вопрос, есть ли способ изменить тип T во время выполнения, так что я могу сделать что-то вроде

generator.SetGeneric<IWeapon>(); 
var weapon = generator.GetRandomObject(); 

любых других способов я мог бы это сделать, если я забираю g неправильный путь?

Спасибо.

+1

Тогда 'generator' больше не является' 'Генератор . Как вы ожидаете, что это будет работать, и как вы хотите это использовать? – Amit

+0

Как сделать генератор статическим и иметь свойство Set вернуть типизированный генератор. Таким образом, вы не создаете экземпляр генератора с заданным типом, но можете динамически устанавливать тип, а затем становиться случайным. – lintmouse

ответ

1

I бы просто использовать общий метод, но не общий класс:

public class Generator 
{ 
    private Random rnd = new Random(); 

    // Make it so you only have to get the interfaces for a given type once. 
    private Dictionary<Type, List<Type>> _typeCache = new Dictionary<Type, List<Type>>(); 

    public T GetRandomObject<T>() 
    { 
     List<Type> types = GetTypes<T>(); 

     int index = rnd.Next(types.Count); 
     return (T)Activator.CreateInstance(types[index]); 
    } 

    private List<Type> GetTypes<T>() 
    { 
     List<Type> types; 

     if (!_typesCache.TryGetValue(typeof(T), out types)) 
     { 
      //can't a generic type constraint that says "implements any interface" so I use this ugly thing... 
      if (!typeof(T).IsInterface) 
       throw new Exception("Generator needs to be instanciated with an interface generic parameter"); 

      types = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(T))).ToList(); 

      _typesCache[typeof(T)] = types; 
     } 

     return types; 
    } 
} 

либо это, либо вам придется просто создать другой генератор для каждого типа, если вы хотите, т o сохранить класс общий.

+0

Я отметил это для решения и реализации typesCache, чтобы сохранить производительность кода. –

1

Вы не можете это сделать ...
Вам не нужен общий класс.
Просто сделайте свои методы универсальными. основном просто объединить весь код в одном методе

public class Generator 
{ 
    public static T GetRandomObject<T>() 
    { 
     if(typeof(T).IsInterface) 
      throw new Exception("Generator needs to be instanciated with an interface generic parameter"); 

     Random rnd = new Random(); 

     var types = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(T))).ToList(); 
     int index = rnd.Next(types.Count); 
     return (T)Activator.CreateInstance(types[index]); 
    } 
} 

Теперь, если вы беспокоитесь о производительности можно кэшировать список, если типы в
словарь < строкой, список < Тип >>

0

Или вы можете генерировать генераторы:

public class Generator<T> 
{ 
    private readonly Random rnd; 
    private List<Type> types = new List<Type>(); 

    public Generator(Random r) 
    { 
     rnd = r; 

     if (!typeof(T).IsInterface) 
      throw new Exception("Generator needs to be instanciated with an interface generic parameter"); 

     types = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.GetInterfaces().Contains(typeof(T))).ToList(); 
    } 

    public T GetRandomObject() 
    { 
     int index = rnd.Next(types.Count); 
     return (T)Activator.CreateInstance(types[index]); 
    } 
} 

public class MetaGenerator 
{ 
    private readonly Random rnd = new Random(); 

    public Generator<T> Create<T>() 
    { 
     return new Generator<T>(rnd); 
    } 
} 

var metaGenerator = new MetaGenerator(); 

var generator = metaGenerator.Create<IEnemy>(); 
generator = metaGenerator.Create<IWeapon>(); 
Смежные вопросы