My function requires you pass it a string and a Type as T. Based on T i want to parse the string val as that type, but I get the error from the title of this question. Anyone that has any insight or other ways of accomplishing this function, I would greatly appreciate it.
T Parse<T>(string val) where T : System.Object
{
TypeCode code = Type.GetTypeCode(typeof(T));
switch (code)
{
case TypeCode.Boolean:
return System.Boolean.Parse(val);
break;
case TypeCode.Int32:
return Int32.Parse(val);
break;
case TypeCode.Double:
return Double.Parse(val);
break;
case TypeCode.String:
return (string)val;
break;
}
return null;
}
Just remove where T : System.Object.
By stating:
where T : System.Object
you're saying that the types T usable in your method Parse must inherit from object.
But, since every object in C# inherits from System.Object you don't need that constraint (and probably that's one of the reasons why the compiler does not allow that).
Also, since you're returning null, you should constraint the type T to be a reference type, so:
where T: class
But in this way you can't return a boolean, integer or whatever value type.
However, your code basically mimics the functionality of Convert.ChangeType, the only difference is that you're using generics to return the correct type instead of object, but is basically equal to this:
T Parse<T>(string val)
{
return (T)Convert.ChangeType(val,typeof(T));
}
Related
I ran into an issue similar to this:
void main() {
_buildMixedList([1,2.3,4,5.6,7.6,8]);
_buildHomogeneousList([1,2,4,5,7,8]);
}
abstract class NumberWrapper {}
class DoubleWrapper extends NumberWrapper{
final double myDouble;
DoubleWrapper(this.myDouble);
}
class IntWrapper extends NumberWrapper{
final int myInt;
IntWrapper(this.myInt);
}
List<NumberWrapper?> _buildMixedList(List<dynamic> numbers) {
List<NumberWrapper?> wrappers = numbers.map((number) {
if(number is int){
return IntWrapper(number);
}
if(number is double){
return DoubleWrapper(number);
}
return null;
}).toList();
wrappers.add(DoubleWrapper(0.2));
return wrappers;
}
List<NumberWrapper?> _buildHomogeneousList(List<dynamic> numbers) {
List<NumberWrapper?> wrappers = numbers.map((number) {
if(number is int){
return IntWrapper(number);
}
return null;
}).toList();
wrappers.add(DoubleWrapper(0.2));
return wrappers;
}
As you can see, the two methods are doing something similar (adding object of different types to a list). The first one adds different objects inside a map() function and the other adds only one type in map() and then adds another after.
The second one throws this error:
: TypeError: Instance of 'DoubleWrapper': type 'DoubleWrapper' is not a subtype of type 'IntWrapper?'Error: TypeError: Instance of 'DoubleWrapper': type 'DoubleWrapper' is not a subtype of type 'IntWrapper?'
As if the list is being changed to List<IntWrapper?> just because we only added IntWrappers in the map().
I wrote this test code after encountering this in one of my projects, so it's not representative of a real case. I tried it on dartPad.
Coming from a java background I was expecting the second method to work. Is it a bug or is it intended? If intended, why is that so?
Your problem is that there are a difference between the type of the variable and the type of the object which you are pointing to.
So in this case:
List<NumberWrapper?> wrappers = numbers.map((number) {
if(number is int){
return IntWrapper(number);
}
return null;
}).toList();
What you are actually are doing is creating a List<IntWrapper?> which you are using a variable of the type List<NumberWrapper?> to point at. Why? Because the type of the variable in this case does not change the type of the returned List from toList() (which type is determined by what type map() returns).
The reason the type is List<IntWrapper?> is because Dart are trying to be smart about automatically assigning the type. In this case, the analyzer can see you List will only contain IntWrapper or null.
I think the best solution here is to rewrite this part to something like this:
List<NumberWrapper?> _buildHomogeneousList(List<num> numbers) {
final wrappers = <NumberWrapper?>[
for (final number in numbers)
if (number is int) IntWrapper(number) else null
];
wrappers.add(DoubleWrapper(0.2));
return wrappers;
}
By using the [] syntax to create the List, it is easier to specify the type you want the List to be.
Alternative, you can do this where we add the expected type to the map method:
List<NumberWrapper?> _buildHomogeneousList(List<num> numbers) {
List<NumberWrapper?> wrappers = numbers.map<NumberWrapper?>((number) {
if (number is int) {
return IntWrapper(number);
}
return null;
}).toList();
wrappers.add(DoubleWrapper(0.2));
return wrappers;
}
Let's say I had some function that takes a generic type as an argument. How do I check within that function whether the generic type argument is nullable or not? I want do something like this:
void func<T>() {
print(T is nullable);
}
void main(){
func<int>(); //prints false
func<int?>(); //prints true
}
All I can think of to do is to check if T.toString() ends with a ? which is very hacky.
Try:
bool isNullable<T>() => null is T;
The accepted answer really just checks if the type can be null. It doesn't care about the type that you are operating the null operator on.
If you want to check if a type is a specific nullable type, a.k.a if you want to check if a type is specifically one of type DateTime? and not String?, you can't do this in dart via T == DateTime? as this conflicts with ternary operator syntax.
However, since dart allows passing nullable types into generic arguments, it's possible to it like so:
bool isType<T, Y>() => T == Y;
isType<T, DateTime?>() works.
I have come across this a lot. And #Irn method works, except for when T is type Type (when using generics), it will always return saying that T is not null.
I needed to test the actual type of Type not Type its self.
This is what I have that is working really well for me.
bool get isNullable {
try {
// throws an exception if T is not nullable
final value = null as T;
return true;
} catch (_) {
return false;
}
}
It creates a new List instance to verify if it's type is nullable or not by using the is operator which supports inheritance:
bool isNullable<T>() => <T?>[] is List<T>;
I am very new to Dart so excuse me if I didnt see this part.
I want to make a union type e.g. for a function input. In TS this would be:
let variableInput: string | number
typedef doesnt really define types but functions and enums dont really help too.
On the other side how should it look like when a function return either one or the other of two types? There must be something I dont see here.
There are no union types in Dart.
The way to do this in Dart is returning/accepting dynamic as a type:
dynamic stringOrNumber() { ... }
void main() {
final value = stringOrNumber();
if (value is String) {
// Handle a string value.
} else if (value is num) {
// Handle a number.
} else {
throw ArgumentError.value(value);
}
}
See also: https://dart.dev/guides/language/sound-dart
I'm reasonably proficient with Groovy insofar as my job requires, but not having a background in OOP means that some things still elude me, so apologies if some of the wording is a little off here (feel free to edit if you can make the question clearer).
I'm trying to create an overloaded method where the signature (ideally) differs only in the return type of the single Closure parameter. The Closure contains a method call that returns either an ItemResponse or ListResponse object, both of which could contain an object/objects of any type (which is the type I would like to infer).
The following code is a simplified version of what I'm trying to implement - an error handling method which takes a reference to a service call, safely attempts to resolve it, and returns the item/items from the response as appropriate:
public <T> T testMethod(Closure<ItemResponse<T>> testCall) {
testCall.call().item as T
}
public <T> List<T> testMethod(Closure<ListResponse<T>> testCall) {
testCall.call().items as T
}
Obviously this doesn't work, but is there any alternate approach/workaround that would achieve the desired outcome?
I'm trying to create an overloaded method where the signature
(ideally) differs only in the return type of the single Closure
parameter.
You cannot do that because the return type is not part of the method signature. For example, the following is not valid:
class Demo {
int doit() {}
String doit() {}
}
As mentioned by yourself and #jeffscottbrown, you can't have two methods with the same parameters but different return value. The workaround I can see here is to use a call-back closure. The return value of your testMethod would default to Object and you would provide an "unwrapper" that would the bit after the closure call (extract item or items). Try this out in your GroovyConsole:
class ValueHolder <T> {
T value
}
Closure<List<Integer>> c = {
[1]
}
Closure<ValueHolder<String>> d = {
new ValueHolder(value:'hello world')
}
Closure liu = {List l ->
l.first()
}
Closure vhsu = {ValueHolder vh ->
vh.value
}
// this is the generic method
public <T> Object testMethod(Closure<T> testCall, Closure<T> unwrapper) {
unwrapper(testCall.call()) as T
}
println testMethod(c, liu)
println testMethod(d, vhsu)
It works with both a list or a value holder.
Assume such conditions:
Some operation does not provide possibility of returning the result.
This operation declared as callback
Using typedef not recommended
Some operation provide of returning the result.
This operation declared as callback
Using typedef not recommended
Assume such scenario:
void main() {
executeVoidOperation(methodNonVoid); // Must throw if method void?
executeNonVoidOperation(methodVoid); // Must throw if method non-void?
}
int methodNonVoid() {
return 0;
}
void methodVoid() {
}
void executeVoidOperation(void operation()) {
operation(); // Must throw if method non-void?
}
void executeNonVoidOperation(dynamic operation()) {
var result = operation(); // Must throw if method void?
print(result); // Result of void operation? (if such passed as argument)
}
Displayed results:
null
Questions (where I wrong?):
Null is object. From where this null appeared (as result) if void function cannot return result (even null)?
Functions with different return types in Dart assumed as the same (not conflicting) types?
How in Dart called this function transformations?
executeNonVoidOperation(methodVoid); works because the callback is defined as dynamic operation(). dynamic can be anything, including void. It's the same as if you just don't specify a type.
The null value stems from a simple rule in Dart. Quoted from the Dart Language Tour:
All functions return a value. If no return value is specified, the statement return null; is implicitly appended to the function body.
That means that every void method always returns null. If you try to return something else, you'll get a runtime error (in checked mode).
executeVoidOperation(methodNonVoid); is a bit more tricky - I'd expect it to throw a runtime error, but it seems the callback is treated as dynamic operation() instead of void operation(). Dart Editor's analyzer seems to think that, too. This may be either a bug or a design choice by the Dart team.