Let's say I have an method:
public void update(List<InputSource<dynamic>> inputs);
InputSource is my own generic class. Ideally, I want the List to be a list of InputSources of any instance of the generic. Is this doable? In other words, I want inputs to be able to hold an InputSource<double>
, an InputSource<string>
, and an InputSource<int>
all in the same instance.
I tried this, but then I tried to use the method:
InputSource<double> ip = new InputSource<double>();
List<InputSource<dynamic>> inputSources = new List<InputSource<dynamic>>(){ip}; //THIS LINE GIVES ME A COMPILE TIME ERROR
update(inputSources);
The labeled line gives me a compiletime error:
Error 6 The best overloaded Add method 'System.Collections.Generic.List<InputSource<dynamic>>.Add(InputSource<dynamic>)' for the collection initializer has some invalid arguments
Cannot convert from 'InputSource<double>' to 'InputSource<dynamic>'
Trying to add an explicit cast:
List<InputSource<dynamic>> inputSources = new List<InputSource<dynamic>>(){(InputSource<dynamic>)inputSource};
gives the following error:
Error 6 Cannot convert type 'InputSource<double>' to 'InputSource<dynamic>'
What is the correct way to achieve my goal here?
Maybe you can change your code like this,all InputSource
based on IInputSource
public interface IInputSource
{
}
public class InputSource<T> : IInputSource
{
}
public void update(IList<IInputSource> inputs)
{
IInputSource ip = new InputSource<double>();
inputs.Add(ip);
}
Change the signature of the update()
method using generics with some constraints
public void update<T>(List<InputSource<T>> inputs) where T:
IComparable,
IComparable<T>,
IConvertible,
IEquatable<T>
// Check the T for safe if you want
Your compile error is not related to the update()
method, there is error when you call the Add()
method:
List<InputSource<dynamic>> inputSourceList = new List<InputSource<dynamic>>();
InputSource<double> ipDouble = new InputSource<double>();
inputSourceList.Add(ipDouble); // illegal
Even casting a InputSource<double>
to InputSource<dynamic>
is illegal, no matter InputSource
is covariant or contravariant, because these variance does not apply to value type (for someone interested, you may try to compile IEnumerable<object> objs = new List<double>()
):
InputSource<dynamic> ipDynamic = ipDouble; // illegal
You may use List<dynamic>
or List<object>
instead of List<InputSource<dynamic>>
for storing a list of different objects.
Here is a variation of Sky Fang's answer that you might like better. Use an abstract class InputSource instead of IInputSource and derive InputSource from that. Then you can do something like the following:
public
abstract class InputSource
{
public InputSource<T> As<T>() { return (InputSource<T>) this; }
protected
abstract Object getValue();
public Object GetValue() { return this.getValue(); }
}
public class InputSource<T> : InputSource
{
public
override object getValue() { return this.GetValue(); }
public
new T GetValue() { /* todo: do something interesting here */ throw new NotImplementedException(); }
}
public void update(IList<InputSource> inputs)
{
inputs.Add(new InputSource<double>());
inputs.Add(new InputSource<int>());
}
With an interface, everything is public. With the abstract class, you can define protected abstract methods and properties, that you override in the generic subclass. You can create methods that are not type safe in the abstract class, and then hide them with type safe equivalents in the generic subclass (like the GetValue method in this example).
And if you still want to use the IInputSource interface, you can have the abstract class implement that.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.