Implementation of Generic Method in List<Class>
-
Hi guys! I'm dealing with a problem I can't find a solution for. What I'm trying to do is this: I have a Model which should contain a generic method (generic input and return value). And furthermore these Models should be merged into a List. And here it gets complicated and I end up in a dead end. Here's the code which hopefully makes it more clear:
class MainClass
{
public static void Main (string[] args)
{
List containers = new List();
containers.Add(new ContainerA());
containers.Add(new ContainerB());} } abstract class ContainerBase { public string Name { get; set; } public abstract TResult Calculate(params TInput\[\] input); } class ContainerA : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override double Calculate(params int\[\] input) { int\[\] ints = input as int\[\]; double result = 0; return result; // !! throws an error return result as TResult; // !! doesn't work either } #endregion } class ContainerB : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override uint Calculate(params uint\[\] input) { throw new System.NotImplementedException (); } #endregion }
This is needed because I want to be able to combine different algorithms (presented by the Model), e.g. Algo 1: combine 3 integers, Algo 2: divide two integers, Algo 3: get the sort via Drag&Drop (in MVVM - hence the unified approach). An Alternative would be to store a whole Metod in a Property in the Model, but it needs to be generic as well. And I have no idea how to do that either. Help would be appreciated!
-
Hi guys! I'm dealing with a problem I can't find a solution for. What I'm trying to do is this: I have a Model which should contain a generic method (generic input and return value). And furthermore these Models should be merged into a List. And here it gets complicated and I end up in a dead end. Here's the code which hopefully makes it more clear:
class MainClass
{
public static void Main (string[] args)
{
List containers = new List();
containers.Add(new ContainerA());
containers.Add(new ContainerB());} } abstract class ContainerBase { public string Name { get; set; } public abstract TResult Calculate(params TInput\[\] input); } class ContainerA : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override double Calculate(params int\[\] input) { int\[\] ints = input as int\[\]; double result = 0; return result; // !! throws an error return result as TResult; // !! doesn't work either } #endregion } class ContainerB : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override uint Calculate(params uint\[\] input) { throw new System.NotImplementedException (); } #endregion }
This is needed because I want to be able to combine different algorithms (presented by the Model), e.g. Algo 1: combine 3 integers, Algo 2: divide two integers, Algo 3: get the sort via Drag&Drop (in MVVM - hence the unified approach). An Alternative would be to store a whole Metod in a Property in the Model, but it needs to be generic as well. And I have no idea how to do that either. Help would be appreciated!
Try
return (TResult)result;
*pre-emptive celebratory nipple tassle jiggle* - Sean Ewington
"Mind bleach! Send me mind bleach!" - Nagy Vilmos
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier
-
Try
return (TResult)result;
*pre-emptive celebratory nipple tassle jiggle* - Sean Ewington
"Mind bleach! Send me mind bleach!" - Nagy Vilmos
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier
Thanks for the hint but no, this doesn't solve my problem:
public override TResult Calculate (params TInput[] input) // !! public override double Calculate(params int[] input)
{
int[] ints = input as int[];
double result = 0;
foreach (int item in ints) {
result += item;
}return (TResult)result; // !! ErrorMessage: Cannot convert type double to TResult }
-
Try
return (TResult)result;
*pre-emptive celebratory nipple tassle jiggle* - Sean Ewington
"Mind bleach! Send me mind bleach!" - Nagy Vilmos
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier
won't work without type limitations, you can't convert just anything to double. And I'm afraid the whole thing cannot be done in C#. :)
Luc Pattyn [My Articles] Nil Volentibus Arduum
-
Hi guys! I'm dealing with a problem I can't find a solution for. What I'm trying to do is this: I have a Model which should contain a generic method (generic input and return value). And furthermore these Models should be merged into a List. And here it gets complicated and I end up in a dead end. Here's the code which hopefully makes it more clear:
class MainClass
{
public static void Main (string[] args)
{
List containers = new List();
containers.Add(new ContainerA());
containers.Add(new ContainerB());} } abstract class ContainerBase { public string Name { get; set; } public abstract TResult Calculate(params TInput\[\] input); } class ContainerA : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override double Calculate(params int\[\] input) { int\[\] ints = input as int\[\]; double result = 0; return result; // !! throws an error return result as TResult; // !! doesn't work either } #endregion } class ContainerB : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override uint Calculate(params uint\[\] input) { throw new System.NotImplementedException (); } #endregion }
This is needed because I want to be able to combine different algorithms (presented by the Model), e.g. Algo 1: combine 3 integers, Algo 2: divide two integers, Algo 3: get the sort via Drag&Drop (in MVVM - hence the unified approach). An Alternative would be to store a whole Metod in a Property in the Model, but it needs to be generic as well. And I have no idea how to do that either. Help would be appreciated!
I'm not a generics specialist, however IMO what you want can't be handled by C# (or any other .NET language) at the moment. IIRC what you want falls under covariance and contravariance and its support is quite limited, see e.g. here[^]. The easiest statement on the subject is this:
List<TextBox> textboxes=new List<TextBox>();
List<Control> controls=textboxes;will not be acceptable: even though a TextBox is a special Control, a list of them can't be "generalized". Same for method return values. :)
Luc Pattyn [My Articles] Nil Volentibus Arduum
-
won't work without type limitations, you can't convert just anything to double. And I'm afraid the whole thing cannot be done in C#. :)
Luc Pattyn [My Articles] Nil Volentibus Arduum
Yeah, I've just looked at his sample and noticed that he declared his value as a double. Too busy looking at the comments that sat "this doesn't work".
*pre-emptive celebratory nipple tassle jiggle* - Sean Ewington
"Mind bleach! Send me mind bleach!" - Nagy Vilmos
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier
-
I'm not a generics specialist, however IMO what you want can't be handled by C# (or any other .NET language) at the moment. IIRC what you want falls under covariance and contravariance and its support is quite limited, see e.g. here[^]. The easiest statement on the subject is this:
List<TextBox> textboxes=new List<TextBox>();
List<Control> controls=textboxes;will not be acceptable: even though a TextBox is a special Control, a list of them can't be "generalized". Same for method return values. :)
Luc Pattyn [My Articles] Nil Volentibus Arduum
As an alternative, is there a chance of storing different kind of functions in a property? Something like Func and Func? Guess it's the same problem,but better asking before throwing the idea over board. Do you have an approach on how this can be achieved? Something that didn't come into my mind? Thank you!
-
Hi guys! I'm dealing with a problem I can't find a solution for. What I'm trying to do is this: I have a Model which should contain a generic method (generic input and return value). And furthermore these Models should be merged into a List. And here it gets complicated and I end up in a dead end. Here's the code which hopefully makes it more clear:
class MainClass
{
public static void Main (string[] args)
{
List containers = new List();
containers.Add(new ContainerA());
containers.Add(new ContainerB());} } abstract class ContainerBase { public string Name { get; set; } public abstract TResult Calculate(params TInput\[\] input); } class ContainerA : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override double Calculate(params int\[\] input) { int\[\] ints = input as int\[\]; double result = 0; return result; // !! throws an error return result as TResult; // !! doesn't work either } #endregion } class ContainerB : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override uint Calculate(params uint\[\] input) { throw new System.NotImplementedException (); } #endregion }
This is needed because I want to be able to combine different algorithms (presented by the Model), e.g. Algo 1: combine 3 integers, Algo 2: divide two integers, Algo 3: get the sort via Drag&Drop (in MVVM - hence the unified approach). An Alternative would be to store a whole Metod in a Property in the Model, but it needs to be generic as well. And I have no idea how to do that either. Help would be appreciated!
Your Calculate method is seriously flawed. You want to use a generic parameter and return type but then fix the types inside the method implementation to int and double! You can use type constraints to ensure that any properties/methods that you need (for conversion or whatever) are supported by the types specified.
Dave
Binging is like googling, it just feels dirtier. Please take your VB.NET out of our nice case sensitive forum. Astonish us. Be exceptional. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) -
As an alternative, is there a chance of storing different kind of functions in a property? Something like Func and Func? Guess it's the same problem,but better asking before throwing the idea over board. Do you have an approach on how this can be achieved? Something that didn't come into my mind? Thank you!
This works for me... not sure if casting to object will cause you any issues or not.
public TResult Calculate<TResult, TInput>(params TInput[] input) // !! public override double Calculate(params int[] input)
{
int[] ints = input as int[];double result = 0; byte test = 4; result = test << 2; return (TResult)(object)result; // cast to object then generic no errors and this sample code runs and returns the expected value of 16 }
-
Your Calculate method is seriously flawed. You want to use a generic parameter and return type but then fix the types inside the method implementation to int and double! You can use type constraints to ensure that any properties/methods that you need (for conversion or whatever) are supported by the types specified.
Dave
Binging is like googling, it just feels dirtier. Please take your VB.NET out of our nice case sensitive forum. Astonish us. Be exceptional. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) -
Hi guys! I'm dealing with a problem I can't find a solution for. What I'm trying to do is this: I have a Model which should contain a generic method (generic input and return value). And furthermore these Models should be merged into a List. And here it gets complicated and I end up in a dead end. Here's the code which hopefully makes it more clear:
class MainClass
{
public static void Main (string[] args)
{
List containers = new List();
containers.Add(new ContainerA());
containers.Add(new ContainerB());} } abstract class ContainerBase { public string Name { get; set; } public abstract TResult Calculate(params TInput\[\] input); } class ContainerA : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override double Calculate(params int\[\] input) { int\[\] ints = input as int\[\]; double result = 0; return result; // !! throws an error return result as TResult; // !! doesn't work either } #endregion } class ContainerB : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override uint Calculate(params uint\[\] input) { throw new System.NotImplementedException (); } #endregion }
This is needed because I want to be able to combine different algorithms (presented by the Model), e.g. Algo 1: combine 3 integers, Algo 2: divide two integers, Algo 3: get the sort via Drag&Drop (in MVVM - hence the unified approach). An Alternative would be to store a whole Metod in a Property in the Model, but it needs to be generic as well. And I have no idea how to do that either. Help would be appreciated!
If you are not absolutely required to use generics, another option would be to create a custom class that has implicit operators to all of the value types you want to support (if you added implicit cast to\from double, then double already can be cast to from int implicitly). just a snippet example
public class testtype { //private constructor private testtype() { } public Type ValueType { get { return \_type; } } //readonly type public object Value { get { return \_value; } } //readonly value private Type \_type = typeof(int); //initally object is integer private object \_value = int.MinValue; //set value to failsafe value //convert to testtype public static implicit operator testtype(int m) { testtype t = new testtype(); t.\_value = m; t.\_type = typeof(int); return t; } //convert to int public static implicit operator int(testtype m) { if (typeof(int).Equals(m.\_type)) return (int)m.\_value; //failsafe value return int.MinValue; } }
example usage
testtype v = 1;
double b = v;
Food for thought...
-
Hi guys! I'm dealing with a problem I can't find a solution for. What I'm trying to do is this: I have a Model which should contain a generic method (generic input and return value). And furthermore these Models should be merged into a List. And here it gets complicated and I end up in a dead end. Here's the code which hopefully makes it more clear:
class MainClass
{
public static void Main (string[] args)
{
List containers = new List();
containers.Add(new ContainerA());
containers.Add(new ContainerB());} } abstract class ContainerBase { public string Name { get; set; } public abstract TResult Calculate(params TInput\[\] input); } class ContainerA : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override double Calculate(params int\[\] input) { int\[\] ints = input as int\[\]; double result = 0; return result; // !! throws an error return result as TResult; // !! doesn't work either } #endregion } class ContainerB : ContainerBase { #region implemented abstract members of Generics.ContainerBase public override TResult Calculate (params TInput\[\] input) // !! public override uint Calculate(params uint\[\] input) { throw new System.NotImplementedException (); } #endregion }
This is needed because I want to be able to combine different algorithms (presented by the Model), e.g. Algo 1: combine 3 integers, Algo 2: divide two integers, Algo 3: get the sort via Drag&Drop (in MVVM - hence the unified approach). An Alternative would be to store a whole Metod in a Property in the Model, but it needs to be generic as well. And I have no idea how to do that either. Help would be appreciated!
I am having way to much fun now... This is the closest I could come up with to what you want and somewhat providing a safe implementation of it. Obviously you would need to implement some checks to avoid crashing if incorrect values are used and I don't know exactly what kind of calculations you are performing but here is what I got.
public override T Calculate<T, P>(params P[] input) where T : IConvertible where P : IConvertible // !! public override double Calculate(params int[] input)
{
TypeCode mode = Type.GetTypeCode(typeof(P));switch (mode) { case TypeCode.Double: //do your calculations for double\[\] //change array to usable format - we know T is double so we can cast them double\[\] args = (double\[\])Convert.ChangeType(input, typeof(double\[\])); //do some math... double r = 0; //obviously you want to verify r = args\[0\] + args\[1\]; return (T)Convert.ChangeType(r, typeof(T)); case TypeCode.Int32: //do your calculations for int32\[\] case TypeCode.Decimal: //do your calculations for decimal\[\] default: break; } throw new NotSupportedException("Generic type value \[" + typeof(T).ToString() + "\] is not supported.");
}
My test usage:
double y = Calculate<int, double>(new double[] { 1.5, 2.25 });
Console.WriteLine(y.ToString()); try { Calculate<string, string>(new string\[\] { "no", "gonna error!" }); } catch (NotSupportedException ex) { System.Diagnostics.Trace.TraceError(ex.Message); }
The trace output from throwing in a string value
Quote:
UnitTest.vshost.exe Error: 0 : Generic type value [System.String] is not supported.
-
I agree, unfortunately you can't restrict to double, int etc. as far as I know. Not sure why he needs it to be generic, suppose he could validate the types being passed in to verify if the generic values coming in are of type int, double etc.
On the rare times I've needed to restrict to a few types, I've created an interface with the required properties/methods and then created concrete wrapper classes around the required type - with implicit conversions - that implement the interfaces. The interface can then be used as a type constraint and all is well in the world :) Edit: Just read your replies below - pretty much where you're heading too I think ;)
Dave
Binging is like googling, it just feels dirtier. Please take your VB.NET out of our nice case sensitive forum. Astonish us. Be exceptional. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) -
I am having way to much fun now... This is the closest I could come up with to what you want and somewhat providing a safe implementation of it. Obviously you would need to implement some checks to avoid crashing if incorrect values are used and I don't know exactly what kind of calculations you are performing but here is what I got.
public override T Calculate<T, P>(params P[] input) where T : IConvertible where P : IConvertible // !! public override double Calculate(params int[] input)
{
TypeCode mode = Type.GetTypeCode(typeof(P));switch (mode) { case TypeCode.Double: //do your calculations for double\[\] //change array to usable format - we know T is double so we can cast them double\[\] args = (double\[\])Convert.ChangeType(input, typeof(double\[\])); //do some math... double r = 0; //obviously you want to verify r = args\[0\] + args\[1\]; return (T)Convert.ChangeType(r, typeof(T)); case TypeCode.Int32: //do your calculations for int32\[\] case TypeCode.Decimal: //do your calculations for decimal\[\] default: break; } throw new NotSupportedException("Generic type value \[" + typeof(T).ToString() + "\] is not supported.");
}
My test usage:
double y = Calculate<int, double>(new double[] { 1.5, 2.25 });
Console.WriteLine(y.ToString()); try { Calculate<string, string>(new string\[\] { "no", "gonna error!" }); } catch (NotSupportedException ex) { System.Diagnostics.Trace.TraceError(ex.Message); }
The trace output from throwing in a string value
Quote:
UnitTest.vshost.exe Error: 0 : Generic type value [System.String] is not supported.