Object.ReferenceEquals returns incorrect results (in Silverlight 3 at least) - silverlight-3.0

I just discovered a very strange behaviour. I have a class with a string property. In the setter of this property I compare the old value with the new value first and only change property if the values differ:
set
{
if ((object.ReferenceEquals(this.Identifier, value) != true))
{
this.Identifier = value;
this.RaisePropertyChanged("Identifier");
}
}
But this ReferenceEquals almost always returns false! Even if I call object.ReferenceEquals("test", "test") in Quick Watch I get false.
How is this possible?

That's because strings are immutable in C#:
The contents of a string object cannot
be changed after the object is
created, although the syntax makes it
appear as if you can do this.
Since you can't modify an existing string reference, there's no benefit in reusing them. The value passed to your property setter will always be a new string reference, except maybe if you do this.Identifier = this.Identifier;.
I'll try to clarify with an example:
string s = "Hello, "; // s contains a new string reference.
s += "world!"; // s now contains another string reference.

Related

How to Serialize an Object to Json in F# excluding defaults and Keeping Enum Names

I thought this would have been easy but I am having issues ticking all the boxes that I need in this.
I need to
Serialize an object to Json
Ignore any properties not set
Use the ENum names instead of integer values
I have generated all the models for this using the Open API Generator based on a .yaml spec.
My first attempt was to get a bit of code from what looks like an old serializer
let json<'t> (myObj:'t) =
use ms = new MemoryStream()
let serialiser: DataContractJsonSerializer = new DataContractJsonSerializer(typeof<'t>)
let settings: DataContractJsonSerializerSettings = new DataContractJsonSerializerSettings()
(new DataContractJsonSerializer(typeof<'t>)).WriteObject(ms, myObj)
Encoding.Default.GetString(ms.ToArray())
This function actually does everything fine - except it copiess the enum numbers instead of names and I can't see an option to make this happpen.
My other attempt is using System.Text.Json.JsonSerializer:
let options
= new JsonSerializerOptions(
)
options.DefaultIgnoreCondition <- JsonIgnoreCondition.WhenWritingDefault
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
let jsonString:string = JsonSerializer.Serialize(shipmentRequest, options)
I have tried a few different things ( including excluding the Enum converter ) and I always get the following error.
Unable to cast object of type 'System.Int32' to type
'System.Nullable`1[Zimpla.Model.ExpressPackageReference+TypeCodeEnum]'
The specific Object ( roughly ) that it is having an issue with is:
[DataContract(Name = "ExpressPackageReference")]
public partial class ExpressPackageReference : IEquatable<ExpressPackageReference>, IValidatableObject
{
......etc
[DataMember(Name = "typeCode", EmitDefaultValue = false)]
public TypeCodeEnum? typeCode
{
get{ return _typeCode;}
set
{
_typeCode = value;
_flagtypeCode = true;
}
}
This particular property is not even set so it should be skipping over it theoretically. It is possible that I am not generating the object correctly
Without understanding all the details here, I think you are asking how you can serialize an object to json while omitting all properties that are null using System.Text.Json.
To accomplish that you have to set the following option:
options.IgnoreNullValues <- true
Here are the docs for this option:
https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.ignorenullvalues?view=net-5.0#System_Text_Json_JsonSerializerOptions_IgnoreNullValues

Why can I ref return an item of an array that only exists inside the method?

I was trying out the new ref returns of C#7.
I am able to compile and build this:
public ref string MisUseRefReturn(int index)
{
string[] array = { "a", "b", "c", "d" };
return ref array[index]; //array[2] gets out of scope when this method returns!
}
According to MSDN: The return value cannot be a local variable in the method that returns it; it must have a scope that is outside the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Cannot return local 'obj' by reference because it is not a ref local."
So why does this compile? When I execute this method, the returned reference shows the correct string.
Think of the array element as if it were an instance field of the array. Imagine your array were:
public class FourElementStringArray
{
public string element0;
public string element1;
public string element2;
public string element3;
}
Then your code is equivalent to:
public ref string MisUseRefReturn(int index)
{
var array = new FourElementStringArray
{
element0 = "a",
element1 = "b",
element2 = "c",
element3 = "d"
};
// TODO: do this dynamically based on index
return ref array.element2;
}
That abides by the piece of documentation you quoted:
It can be an instance or static field of a class, or it can be an argument passed to the method.
Is this useful? Not particularly. Is it dangerous? No.
The latter part is the important point. Using the regular array, if the caller assigns a new value, that's fine - it's replacing an element of an array, on the heap. The array can't be garbage collected while the array element reference exists; all is basically okay.
What the compiler rule is trying to prevent is the use of a returned reference to somewhere on the stack which has then been popped by the method returning. The array itself isn't on the stack, so there's no problem here.
See the description here:
Returning a local int variable instead of an array is not possible.
int is a value type, and thus the variable gets out of scope at the
end of the method, and thus a reference to it cannot be returned.
That’s different with an array. An array is a reference type, and the
array is allocated on the heap. An int within the array can be
returned with the ref keyword.
You could not return an integer value directly as it is a value type. An array element can be returned because it is a reference type. The MSDN statement is correct.
... of an array that only exists inside the method
The returned reference persists the array beyond the method call.

Attempting to map dates to index in ElasticSearch

I am using ElasticSearch and attempting to create an index with a class that has a dynamic type property in it. This property may have strings or dates in it. When indexing, I have been using the code below:
dynamic instance = MyObject.GetDynamicJson();
var indexResponse = client.Index((object) instance, i=>i
.Index("myIndex")
.Type("MyObject")
);
Here's the code for GetDynamicJson().
MyObject has only Name and Value as properties. (apologies, I've had issues in the past with Elastic choking on json without all the quotes, which I have escaped with \ characters):
String json = "{ \"Name\":\" + Name + "\",\"DateValue\":\"";
try {
var date = DateTime.parse(Value);
json += DateTime.ToString("yyyy/MM/dd HH:mm:ss Z") + "\", \"Value\":\"\"}";
} catch { //If the DateTime parse fails, DateValue is empty and I'll have text in Value
json += "\",\"Value\":\"" + Value + "\"}";
}
return json;
For some reason it doesn't seem to like the string in DateValue and I definitely don't know why it's leaving out that property entirely in the error:
For whatever reason, ElasticSearch is completely dumping the DateValue property, doesn't seem to see the DateValue property at all.
I'm getting the error:
{"name":"CreatedDate","value":"2017-11-07T13:37:11.4340238-06:00"}
[indices:data/write/bulk[s][p]]"}],"type":"class_cast_exception","reason":"org.elasticsearch.index.mapper.TextFieldMapper cannot be cast to org.elasticsearch.index.mapper.DateFieldMapper"},"status":500
Later note: I have changed the index creator method to update the mapping. I added a third field to the Object, so now it has properties: Name, Value, DateValue:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
Now, it is successfully mapping and creating a property each time, but it still seems to drop the property I am sending it in the json. It just sets them all to the default datetime: "dateValue": "0001-01-01T00:00:00". This is strange, because when making the dynamic instance I send to Elastic, I use only the MyObject.GetDynamicJson() method to build it. I no longer get the mapping error, but Elastic still seems oblivious to "dateValue":"some date here" in the object when it is set.
OK, I got rid of the dynamic object type (ultimately I wasn't actually getting data from the json method, I had a typo and Elastic was getting the original object directly - it's a wonder it was still handling it). So I let Elastic do the parse using its mapping. In order to do that, I first updated MyObject to include multiple properties, one for each type the incoming property could be (I am only handling text and dates in this case). For the DateValue property of MyObject, I have this:
public DateTime DateValue {
get
{
try
{
return DateTime.Parse(Value);
} catch
{
return new DateTime();
}
}
set
{
try {
DateValue = value;
} catch
{
DateValue = new DateTime();
}
}
}
Now, if Value is a date, my DateValue field will be set. Otherwise it'll have the default date (a very early date "0001-01-01T00:00:00"). This way, I can later search both for text against that dynamic field, or if a date is set, I can do date and date range queries against it (technically they end up in two different fields, but coming from the same injested data).
Key to this is having the index mapping setup, as you can see in this method from the question:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
In order to recreate the index with the updated MyObject, I did this:
if (client.IndexExists("myIndex").Exists)
{
client.DeleteIndex("myIndex");
CreateRecordsIndex(client); //Goes to the method above
}

Swift: Dictionary passed as parameter is always empty

I want to fill Dictionary via a method of which dictionary is one of the parameter. When I add a value to key, say 15, it always return 0 count when I try to access it second time with same key i.e. 15. Here's the code.
private static var showWidgetMap = Dictionary<Int, [BaseWidget]>()
private static var hideWidgetMap = Dictionary<Int, [BaseWidget]>()
static func initHandler()
{
let cloudWidget = CloudWidget()
cloudWidget.setType(CreatorConstants.CLOUD)
let property1 = [CreatorConstants.IMG_SRC: "cloud1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "450"]
cloudWidget.setPropery(property1)
addWidgetInLocalTimeList(15, widget: cloudWidget, delete: false)
let emojiWidget = CloudWidget()
emojiWidget.setType(CreatorConstants.EMOTICON)
let property2 = [CreatorConstants.IMG_SRC: "1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "550"]
emojiWidget.setPropery(property2)
addWidgetInLocalTimeList(15, widget: emojiWidget, delete: false)}
static func addWidgetInLocalTimeList(time_milisec: Int, widget: BaseWidget, delete: Bool)
{
if(delete)
{
checkAndAdd(hideWidgetMap, key: time_milisec, widget: widget);
}
else
{
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget);
}
}
private static func checkAndAdd(var map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
{
print("map count is")
print(map.count)
if var val = map[key]
{
val.append(widget);
}
else
{
var temp: [BaseWidget] = [];
temp.append(widget);
map[key] = temp
print(map.count)
}
}
print(map.count) always returns 0.
You need to understand the difference between value types and reference types.
Value type variables are just values. For example, an array is a value type. It is just a value of "a bunch of stuff" *. On the other hand, reference types are references to values. For example, when you create a UIViewController, that variable actually stores a reference to the actual UIviewController *.
Don't really understand? Then it's analogy time! The variables and constants you create are children. The things you put in variables and constants are balloons.
There are two types of children, one type (value types) likes to hold balloons directly in their hands. The other type (reference types) likes to hold balloons using a string **.
When you pass a child to a method, depending on what type of child he is, different things will happen:
A value type child holds the balloon in his hands, so tightly that the method parameter can't take it away from him. So what can it do? It creates a copy of it! It then takes the copy to the method implementation let it do its thing.
A reference type, however, holds balloons using a string. The method parameter will tie another string to the balloon so the implementation can access it using the string. As a result, no copies of the balloon are created.
So what are you doing wrong here?
Since swift dictionaries are value types, when you pass a dictionary to a method, as I said above, it creates a copy! In the implementation, you are actually editing a copy of the dictionary, not the original one. That's why the original dictionary still has a count of 0.
What can you do?
Instead of marking the parameter with var, which is a very bad practice btw, you mark it with inout!
private static func checkAndAdd(inout map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
The inout modifier basically says
Hey parameter, next time you see a value type, just get a string and tie it to the balloon that the child is holding.
There is also another thing that you should do. That is you should change the way you call your method.
Instead of
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget)
You write
checkAndAdd(&showWidgetMap, key: time_milisec, widget: widget)
And magically, it works!
Conclusion: Parameters are dumb. They aren't even smart enough to know when to tie a string. Be careful when you work with value types.
Footnotes * Assume it is not nil
** Not the String type, but an actual string.

What exactly does var x:* mean in actionscript?

Its a little tricky to search for 'var:*' because most search engines wont find it.
I'm not clear exactly what var:* means, compared to say var:Object
I thought it would let me set arbitrary properties on an object like :
var x:* = myObject;
x.nonExistantProperty = "123";
but this gives me an error :
Property nonExistantProperty not found on x
What does * mean exactly?
Edit: I fixed the original var:* to the correct var x:*. Lost my internet connection
Expanding on the other answers, declaring something with type asterisk is exactly the same as leaving it untyped.
var x:* = {};
var y = {}; // equivalent
However, the question of whether you are allowed to assign non-existant properties to objects has nothing to do with the type of the reference, and is determined by whether or not the object is an instance of a dynamic class.
For example, since Object is dynamic and String is not:
var o:Object = {};
o.foo = 1; // fine
var a:* = o;
a.bar = 1; // again, fine
var s:String = "";
s.foo = 1; // compile-time error
var b:* = s;
b.bar = 1; // run-time error
Note how you can always assign new properties to the object, regardless of what kind of reference you use. Likewise, you can never assign new properties to the String, but if you use a typed reference then this will be caught by the compiler, and with an untyped reference the compiler doesn't know whether b is dynamic or not, so the error occurs at runtime.
Incidentally, doc reference on type-asterisk can be found here:
http://livedocs.adobe.com/labs/air/1/aslr/specialTypes.html#*
(The markup engine refuses to linkify that, because of the asterisk.)
It's a way of specifying an untyped variable so that you can basically assign any type to it. The code
var x:* = oneTypeObject;
creates the variable x then assigns the oneTypeObject variable to it. You can assign an entirely different type to it as well as follows:
var x:* = anotherTypeObject;
However, you still can't arbitrarily set or access properties; they have to exist in the underlying type (of either oneTypeObject or anotherTypeObject).
Both types may have identically named properties which means you can access or set that property in x without having to concern yourself with the underlying type.
It's the "untyped" type. It just means that the variable can be of any type. Basically the same effect as using this:
var x = myObject;
It means that the type is not specified and can be used with any type. However, you can't set random properties on it. It will behave like whatever type you set it to. The exact syntax is:
var x:*;
As they said before, it's untyped, so it may hold any kind of data. However, you cannot treat it as such in operations. For example, this is valid code:
var untyped:* = functionThatReturnsSomeValue();
But if you go one step farther, you have to watch out or you might get bitten:
var name:String = untyped.name;
Now, if the object returned by that function happens to be an object with a field with an id of "name," you are in the clear. However, unless you know for sure that this is the case, it's better to use typed objects. In this way, the compiler will alert you if you do something that might throw an error at runtime:
(elsewhere)
public class TypedObject()
{
public var name:String = "";
}
(and the code at hand)
var typed:TypedObject = functionThatReturnsTypedObject();
var name:String = typed.name;

Resources