-2

I run into a compiler error that I am not sure how to resolve it.

Basically, I have a few enum classes described below.

I created abstract classes myTool and myTools deriving from myTool. The compiler for some reason does not like the way I structured the constructor for MyTools and threw error

CS0030: Can not convert type int to type T.

Please advice me how to resolve this.

public enum TOOLS
{
  HAMMER =1,
  DRILL = 2,
  SCREWDRIVER =3,
  VACUUM=4
}

public enum EQUIPMENTS
{
  MOWER=1,
  TRIMMER=2,
  SNOWBLOWER=3
}

public abstract class MyTool
{
  protected T _myStuff
  int quantity
  double price
  public MyTool(T t)
  {
  _myStuff =t;
  }
  ... properties...
}

public abstract class MyTools<T>:myTool<T>
where T:System.Enum
{
  protected MyTool<T>[] _myTools;
  public MyTool<T> this[int i]=> this._myTools[i];
  public MyTools(int count, T t):base(t)
  {
    _myTools = new MyTools<T>[count];
    for (int i=0; i<count;i++)
    {
      _myTools[i]=(T)(i+1);
    }
  }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
user1205746
  • 3,110
  • 11
  • 44
  • 73
  • 3
    `public abstract class MyTools:myTool` that's a really, really, really terrible idea to have both a `MyTools` type and a `myTools` type. Really terrible idea... –  Nov 24 '22 at 18:42
  • 1
    `_myTools[i]` is a `MyTool` object, how can you assign a `T`? Do you have an implicit operator? -- This composition seems quite convoluted – Jimi Nov 24 '22 at 19:21
  • @Jimi: That is the problem and Olivier has pointed out... I am new to generic class and made mistakes – user1205746 Nov 24 '22 at 19:26
  • @user1205746 I'd strongly recommend sticking with default language naming guidelines for *public examples*. Naming a type with lowercase or all upper case is unusual and potentially confusing. Please re-read the [mre] guidance - there is zero requirements for code in SO question to match your private version as long as it demonstrates the problem. Note that [codereview.se] guidance is obviously opposite as they review the actual code. – Alexei Levenkov Nov 24 '22 at 21:48

2 Answers2

1

You can convert an int into a generic type constrained as System.Enum like this:

T enumValue = (T)Enum.ToObject(typeof(T), intValue);

or simply

T enumValue = (T)(object)intValue;
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • I appreciate you hint. However, when I changed my assignment to _myTools[i] = (T)Enum.ToObject(typeof(T), (i+1)) or your other suggestion, I got can not implicit convert type T to MyTools – user1205746 Nov 24 '22 at 18:59
  • 1
    But you will get a recursion if you do this in the constructor. Probably the declaration should be `protected T[] _myTools;` and then my solution will work. – Olivier Jacot-Descombes Nov 24 '22 at 19:11
  • Thanks again. You are right, when I changed to (MyTool)Enum.ToObject(typeof(MyTool),(i+1)); it seems to work!.. I can not new since this is an abstract class – user1205746 Nov 24 '22 at 19:16
  • The question is what do you want to add to `_myTools`? If you add another `MyTools`, this will call the constructor recursively, because creating this object call the constructor again creating yet another `MyTools`, and so on... Maybe you should make `MyTool` not abstract and add `MyTool` objects to the array. – Olivier Jacot-Descombes Nov 24 '22 at 19:20
  • Your object model allows you to create tools containing tools containing tools... It that that intentional? – Olivier Jacot-Descombes Nov 24 '22 at 19:27
  • My intention was to be able to generate different classes of tools (defined by the enum).. In MyTools, I can have different instances of MyTool... does it make sense? Then another class like myFactory will be a concrete class inheriting MyTools.. Maybe my design is not good – user1205746 Nov 24 '22 at 19:34
  • 1
    Having a class hierarchy of tools basically makes the enums superfluous. You would have a hierarchy like `Tool` > `Equipment` > `Trimmer` (all non-generic). You can then test `tool is Trimmer` instead of `tool.myStuff = EQUIPMENT.TRIMMER` or something like this. Maybe `MyTools` should not derive from `MyTool` and be called `ToolCollection` instead `where T : Tool`. – Olivier Jacot-Descombes Nov 24 '22 at 20:04
  • Ah.. using collection is the better alternative.. Thanks again, Olivier – user1205746 Nov 24 '22 at 21:43
  • Note that `(T)(object)intValue` conversion blows up at run-time if enum is not int-based (like `enum X : long {Foo, Bar};`), so avoiding whole "increment enum value" problem is better option if possible, otherwise `Enum.ToObject` is the way to go. – Alexei Levenkov Nov 24 '22 at 21:45
  • @AlexeiLevenkov: Yeah, It did! I originally had that and it blew up at run time.. – user1205746 Nov 24 '22 at 21:46
0

You can use generic type converter

public static class TConverter
{
 public static T ChangeType<T>(object value)
 {
     return (T)ChangeType(typeof(T), value);
 }

 public static object ChangeType(Type t, object value)
 {
    TypeConverter tc = TypeDescriptor.GetConverter(t);
    return tc.ConvertFrom(value);
 }

 public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
 {

    TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
 }
}

and usage:

 TConverter.ChangeType<T>(intValue); 

it is from here: https://stackoverflow.com/a/1833128/2286743

d00lar
  • 802
  • 7
  • 25