main(){
String? string1;
String? string2;
String string3;
if(string1!=null)
string3=string1; // No Error
}
But
main(){
String? string1;
String? string2;
String string3;
if(string2!=null && string1==string2)
string3=string1; // Error !
}
I am unable to understand the logic behind this. I think this has something to do with the dart compiler.
Even though you understand the process that string2 is not null and string2 == string1 (Hence string1 must not be null) the compiler just check that you validated the variable you want to use (and because you didn't check string1 != null it doesn't know the variable is not null). another example would be a class with a getter String?
class MyClass {
final String _value = 'notEmpty';
String? get value => _value;
}
You already know the getter returns _value and is of type String but the getter is always of type String? and you have to validate it each time
main(){
final c = MyClass();
String? string1 = c.value;
String? string2;
String string3;
if(string2!=null && string1==string2)
string3=string1; // Error because the compiler think at some point you could just send a String?!
if (c.value != null) {
string3 = c.value; // Error because the compiler think at some point you could just change c-value to a String?!
}
}
For this cases you have a tool ! so even if the compiler doesn't understand it you already check it and told them that it's ok, that you're sure that value is of type String
if(string2!=null && string1==string2)
string3 = string1!; // OK
if (c.value != null) {
string3 = c.value!; // OK
}
Related
in Swift or Kotlin I can do something like this
var fullName = myMap["fullName"] as? String
then as a result that fullName data type will be optional String ( String? ).
I need to get optional type after type checking like that
I can't directly perform null coalescing operator to that map, because dart will give weird result. for example like this
// 'data' is Map<String, dynamic>
final fullName = data["fullname"] ?? "John Doe";
final double myNumber = fullName;
as you can see, the IDE will not show an error at all, I expect that fullName will be a String, so it will have an error when I assign a String to myNumber that require double.
If you know in advance that data["fullname"] is a String, then you could do:
final fullName = (data["fullname"] ?? "John Doe") as String;
If data["fullname"] turns out not to be a String at runtime, you'll get a runtime exception from the cast failure. If that's something you need to handle, then you could easily make a trivial helper function that checks if a dynamic value is the desired type first and that returns null if it isn't:
T? tryCast<T>(dynamic object) => object is T ? object : null;
final fullName = tryCast<String>(data["fullname"]) ?? "John Doe";
and now fullName is statically known to be a String, and accidentally assigning it to a double will be a compile-time error.
The safe nullable cast operator known from Kotlin currently doesn't exist in Dart but it soon might.
In your case though, why not simply write
String? fullname = myMap["fullname"];
The nullable cast operator as? in Kotlin yields null if myMap["fullname"] contains anything but a non-null String. As long as you're only dealing with Strings or null, the above works just fine. (And if there's anything but a String or null it crashes, which is probably better than just continue on with null in most situations)
I have this code . The class is generic and when I instantiate it by passing a String Type. The variable becomes a string type. However the statement
if(_val is String){
}
doesnt seem to be true. Any idea why ?
This is the full code:
class foo<T>{
T _val;
QVar()
{
//Read the value from preferences
if(_val is String){
... //Does not come in here!!
}
}
}
a = new foo<String>();
Instead of
if(T is String)
it should be
if(_val is String)
The is operator is used as a type-guard at run-time which operates on identifiers (variables). In these cases, compilers, for the most part, will tell you something along the lines of T refers to a type but is being used as a value.
Note that because you have a type-guard (i.e. if(_val is String)) the compiler already knows that the type of _val could only ever be String inside your if-block.
Should you need to explicit casting you can have a look at the as operator in Dart, https://www.dartlang.org/guides/language/language-tour#type-test-operators.
Use .runtimeType to get the type:
void main() {
var data_types = ["string", 123, 12.031, [], {} ];`
for(var i=0; i<data_types.length; i++){
print(data_types[i].runtimeType);
if (data_types[i].runtimeType == String){
print("-it's a String");
}else if (data_types[i].runtimeType == int){
print("-it's a Int");
}else if (data_types[i].runtimeType == [].runtimeType){
print("-it's a List/Array");
}else if (data_types[i].runtimeType == {}.runtimeType){
print("-it's a Map/Object/Dict");
}else {
print("\n>> See this type is not their .\n");
}
}}
I have a varible containing an object which might be null. When trying to call a method I have to check for null. I want the result to be false if the variable is null. What is considered good and readable style to to this?
e.g.
class MyClass {
bool boolMethod() {
return true;
}
}
void main() {
MyClass mc = new MyClass();
MyClass mcnull = null;
bool val1 = mc?.boolMethod();
bool val1null = mcnull?.boolMethod();
bool val2 = mc != null && mc.boolMethod();
bool val2null = mcnull != null && mcnull.boolMethod();
}
Especially when used in if-statements I consider the first version much more readable:
if (mc?.boolMethod())...
versus
if (mc != null && mc.boolMethod())...
But IntelliJ gives me the hint The value of the '?.' operator can be 'null' which isn't appropriate as an operand of a locaical operator. (null_aware_in_logical_operator). Ok - this is right because when the variable is null then I use the null as a boolean value. But it's ok in my case and I try to avoid suppressing warnings.
What is the suggested way? Other ideas?
I think a common pattern is
bool val1 = (mc?.boolMethod() ?? false);
The parens aren't required here but if such expressions are embedded into more complex expressions they are often necessary to get the expected behavior because of the low priority of ??
So I can't figure this out, am I supposed to change the '.text' to something else or do I have to go about converting the string into a double?
Here is the code
if item != nil {
// the errors I keep getting for each one is
unitCost.text = item?.unitCost //cannot assign to a value 'NSNumber?' to a value of type 'String?'
total.text = item?.total //cannot assign to a value 'NSNumber?' to a value of type 'String?'
date.text = item?.date //cannot assign to a value 'NSDate?' to a value of type 'String?'
}
You are trying to assign an invalid type to the text property. The text property is of type String? as stated by the compiler error. You are trying to assign an NSNumber or NSDate. The expected type is a String or nil and so you must ensure that you provide only those two possibilities. As a result, you need to convert your numbers and dates into strings.
In Swift, there is no need to use format specifiers. Instead, best practice is to use string interpolation for simple types like numbers:
unitCost.text = "\(item?.unitCost!)"
total.text = "\(item?.total!)"
For dates, you can use NSDateFormatter to produce a human-friendly date in a desired format:
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
date.text = "\(formatter.stringFromDate(date))"
While we're at it, why not use optional binding instead of nil comparison:
if let item = item {
// Set your properties here
}
Try this:
unitCost.text = String(format: "%d", item?.unitCost?.integerValue)
You can add an extension for Double/NSNumber/NSDate
extension Double {
func toString() -> String {
return NSNumberFormatter().stringFromNumber(self) ?? ""
}
}
extension NSNumber {
func toString() -> String {
return NSNumberFormatter().stringFromNumber(self) ?? ""
}
}
var doubleValue: Double?
doubleValue?.toString()
if doubleValue is not set it returns empty string. You can make toString() return String? too.. depends on what you need
also, item != nil check is not required in your code as it is optional.
#dbart "\(item?.unitCost)" displays an optional value as String, like Optional(5) rather than 5, we need to unwrap the value
check this code:
if let requiredItem = item {
unitCost.text = requiredItem.unitCost ? "\(requiredItem.unitCost)" : ""
total.text = requiredItem.total ? "\(requiredItem.total)" : ""
date.text = requiredItem.date ? "\(requiredItem.date)" : ""
}
I'm getting this error:
ex = {"The binary operator Equal is not defined for the types 'MySite.Domain.DomainModel.EntityFramework.NickName' and 'System.Int32'."}
What I tried to do was do a select all where the NickNameId = someIntPassedIn... the problem is that the NickNameId is a foreign key, so when it compares the someIntPassedIn to the NickNameId it pulls the whole NickName object that the NickNameId refers to and tries to compare the int to that object.
I need a solution here to allow it to compare the int to the NickName object's Id... so
A) How can I define the binary operator Equal for comparing these two objects
OR
B) How can I compare it directly to the id instead of the whole object?
You don't have to read this, but here's the SelectAllByKey method incase it helps: (I passed in "NickNameId" and "1")
public IList<E> SelectAllByKey(string columnName, string key)
{
KeyProperty = columnName;
int id;
Expression rightExpr = null;
if (int.TryParse(key, out id))
{
rightExpr = Expression.Constant(id);
}
else
{
rightExpr = Expression.Constant(key);
}
// First we define the parameter that we are going to use the clause.
var xParam = Expression.Parameter(typeof(E), typeof(E).Name);
MemberExpression leftExpr = MemberExpression.Property(xParam, this._KeyProperty);
int temp;
BinaryExpression binaryExpr = MemberExpression.Equal(leftExpr, rightExpr);
//Create Lambda Expression for the selection
Expression<Func<E, bool>> lambdaExpr = Expression.Lambda<Func<E, bool>>(binaryExpr, new ParameterExpression[] { xParam });
//Searching ....
IList<E> resultCollection = ((IRepository<E, C>)this).SelectAll(new Specification<E>(lambdaExpr));
if (null != resultCollection && resultCollection.Count() > 0)
{
//return valid single result
return resultCollection;
}//end if
return null;
}
Let me know if you need any more info.
Thanks,
Matt
You should call SelectAllByKey('NickName.ID','1').
Since ID is property of property, you could use this extension method:
public static MemberExpression PropertyOfProperty(this Expression expr,string propertyName)
{
var properties = propertyName.Split('.');
MemberExpression expression = null;
foreach (var property in properties)
{
if (expression == null)
expression = Expression.Property(expr, property);
else
expression = Expression.Property(expression, property);
}
return expression;
}
The accepted answer seems way too complicated for the problem at hand, if I'm reading this correctly.
If I understand you correctly, you're trying to run a query like:
var q = from e in Context.SomeEntities
where e.NickNameId == someIntPassedIn
select e;
...but this won't work, because e.NickNameId is an entity, not an integer.
To reference the Id property, you can just refer to it, like this:
var q = from e in Context.SomeEntities
where e.NickNameId.Id == someIntPassedIn
select e;
Update: If you can't use strong-typed properties due to your level of abstraction (per your comment), then use query builder methods:
var q = (ObjectQuery<T>)Repository.SelectSomething();
return q.Where("it.NickName.Id = " + someIntPassedIn.ToString());
You can adapt this as you see fit, but the general point is that the EF already knows how to translate strings to property members.