Came across protobuf-net, awesome! I have a question regarding serialization of empty lists.
I start by declaring the object I want to serialize:
[ProtoContract]
class TestClass
{
[ProtoMember(1)]
List<int> _listOfInts = new List<int>();
public TestClass() { }
public List<int> ListOfInts
{
get { return _listOfInts; }
set { _listOfInts = value; }
}
}
If _listOfInts is empty (but not null) when I deserialse this object is will always be null. This makes sense looking at the protobuf convention and I currently work around this by adding the following method:
[ProtoAfterDeserialization]
private void OnDeserialize()
{
if (_listOfInts == null)
_listOfInts = new List<int>();
}
My question is whether I can achieve this same functionality in a more concise fashion, possibly with an additional attirbute which will initialise null/empty objects as empty instead of null?
There's a fundamental issue here in terms of how protobuf encodes data: the list itself does not appear in the data - just the elements. Because of this, there is simply nowhere obvious to store information about the list. It can be spoofed by sending a Boolean using conditional serialization, but frankly that is a bit hacky and ugly - and adds complexity. Personally, I strongly advise abstracting away from lists that could ever be null. For example:
private readonly List<Foo> items = new List<Foo>();
[ProtoMember(1)]
public List<Foo> Items { get { return items; } }
Or
private List<Foo> items;
[ProtoMember(1)]
public List<Foo> Items { get { return items ?? (items = new List<Foo>()); } }
And note that this advice isn't just about serialization: it is about avoiding arbitrary null-reference-exceptions. People don't usually expect sub-collections to be null.
If you are trying to protect against a null list you could try lazy loading in the property getter.
public List<int> ListOfInts
{
get { return _listOfInts ?? (_listOfInts = new List<int>()); }
set { _listOfInts = value; }
}
This way you can just allow the serializer to return null.
Related
I have a readonly List so I can hide the Add method from other classes, like this:
class Foo
{
private readonly List<Bar> _Bars = new List<Bar>;
public()
{
this.Bars = _Bars.AsReadOnly();
}
public ReadOnlyCollection<Bar> Bars
{
get;
private set;
}
public void AddBar(Vector Dimensions)
{
_Bars.Add(new Bar(Dimensions));
}
}
The thing is, now I want to order the _Bars field of an instance of Foo, like such:
public void OrderBarsByVolume()
{
_Bars.OrderByDescending(o => o.Volume); //Doesn't do anything
_Bars = _Bars.OrderByDescending(o => o.Volume).ToList(); //Error: A readonly field cannot be assigned to
}
Is it possible to use orderby and keep the add feature of the List hidden from other classes?
Use List<T>.Sort method
_Bars.Sort((x,y) => x.Volume.CompareTo(y.Volume));
Not with your current implementation, however, if you adjust things slightly then yes you can. The idea of "hiding" the underlying data means you don't have to hold it internally as read only but rather expose it as read only
private List<Bar> _Bars = new List<Bar>();
public ReadOnlyCollection<Bar> Bars
{
get { return _Bars.AsReadOnly(); }
}
public void OrderBy(Func<Bar, bool> src)
{
_Bars = _Bars.OrderByDescending(src);
}
...
var foo = new Foo();
foo.OrderBy(x => x.Volume);
If you feel creating a new ReadOnlyCollection each time is too expensive then keep your code as it is but simply remove the readonly modifier
private List<Bar> _Bars = new List<Bar>;
public void OrderBy(Func<Bar, bool> src)
{
_Bars = _Bars.OrderByDescending(src).ToList();
}
Add a public method that will do the ordering within the Foo object.
Even if James gave you some good tips, there are still some open issues.
So let's start with your implementation:
private readonly List<Bar> _Bars = new List<Bar>;
This won't make the list itself read-only. Still it is possible to add, remove an item or to clear the entire list. The keyword readonly only ensure that you can't replace the whole list by a completely different list.
So what you like, is that within your class you have full access to the list (so Foo can add, remove, sort items), but anybody who requested the list, can only read this list. The open question here would be what should happen if someone requested the list and afterwards the list was changed from Foo. Should the already outgiven list reflect theses changes or not? Mostly you like this behaviour, but it really depends on what you like to achieve.
Here is my code example that should solve most of your problems:
internal class Foo
{
// The list which can be manipulated only be Foo itself.
private List<Bar> _Bars;
// The proxy that will be given out to the consumers.
private ReadOnlyCollection<Bar> _BarsReadOnly;
public Foo()
{
// Create the mutable list.
_Bars = new List<Bar>();
// This is a wrapper class that holds a
// reference to the mutable class, but
// throws an exception to all change methods.
_BarsReadOnly = _Bars.AsReadOnly();
}
public IReadOnlyList<Bar> Bars
{
// Simply give out the wrapper.
get { return _BarsReadOnly; }
}
public void AddBar(Vector dimensions)
{
// Manipulate the only intern available
// changeable list...
_Bars.Add(new Bar(dimensions));
}
public void SortBars()
{
// To change the order of the list itself
// call the Sort() method of list with
// a comparer that is able to sort the list
// as you like.
_Bars.Sort(BarComparer.Default);
// The method OrderBy() won't have any
// immediate effect.
var orderedList = _Bars.OrderBy(i => i.Volume);
// That's because it will just create an enumerable
// which will iterate over your given list in
// the desired order, but it won't change the
// list itself and so also not the outgiven wrappers!
}
}
To use the Sort() method of the list class you need an comparer but that's quite easy to implement:
internal class BarComparer : IComparer<Bar>
{
public static BarComparer Default = new BarComparer();
public int Compare(Bar x, Bar y)
{
if (ReferenceEquals(x, y))
return 0;
if (ReferenceEquals(x, null))
return -1;
if (ReferenceEquals(y, null))
return 1;
return x.Volume.CompareTo(y.Volume);
}
}
I hope this gives you a little more enlightenment about how stuff in C# works.
Let the callers handle the sorted list:
public IEnumerable<Bars> OrderedBars(Func<Bar, bool> sortMethod)
{
return _Bars.OrderBy(sortMethod);
}
If you really want to keep the sorted bars to yourself, you could create a immutable class where ordering the bars create a new instance of Foo which will then either replace the current one or be used by the caller, something like that:
public Foo OrderBarsByVolume()
{
return new Foo() {_Bars = this._Bars.OrderByDescending(o => o.Volume)}
}
Currently I have object which contains two strings:
class myClass
{
public string string1 { get; set; }
public string string2 { get; set; }
public bool MatcheString1(string newString)
{
if (this.string1 == newString)
{
return true;
}
return false;
}
}
I then have a second class that makes a list of the aforementioned object using List.
class URLs : IEnumerator, IEnumerable
{
private List<myClass> myCustomList;
private int position = -1;
// Constructor
public URLs()
{
myCustomList = new List<myClass>();
}
}
In that class I’m using a method to check if a string is present in the list
// We can also check if the URL string is present in the collection
public bool ContainsString1(string newString)
{
foreach (myClass entry in myCustomList)
{
if (entry. MatcheString1(newString))
{
return true;
}
}
return false;
}
Essentially, as the list of objects grows to the 100,000 mark, this process becomes very slow. What is fast way to checking if that string is present? I’m happy to create a List outside of the class to validation, but that seems hacky to me?
Once the list of items is stable, you can compute a hash-set of the matches, for example:
// up-front work
var knownStrings = new HashSet<string>();
foreach(var item in myCustomList) knownStrings.Add(item.string1);
(note that this is not free, and will need to be re-computed as the list changes); then, later, you can just check:
return knownStrings.Contains(newString);
which is then very cheap (O(1) instead of O(N)).
If you don't mind using a different data structure, instead of a list, you could a dictionary where your objects are indexed by their string1 property.
public URLs()
{
myDictionary = new Dictionary<string, myClass>();
}
Since Dictionary<TKey, TValue> can usually find elements in O(1) time, you can perform that check very fast.
if(myDictionary.ContainsKey(newString))
//...
Search over sorted array(list) takes O(logN)
var sortedList = new SortedSet<string>();
sortedList.Add("abc");
// and so on
sortedList.Contains("test");
Search over HashSet takes O(1), but I guess in case of 100k elements(Log(100000)=5), and almost no difference to the HashSet that takes more memory.
I'm trying to write safeAdd extention function for List class, so if it's not initialized yet - initialize it and add new value. But after I return from extension method, my just initialized list equals null. What's wrong?
Test class:
private class Test
{
public Test()
{
Id = Guid.NewGuid();
//items = new List<string>();
}
public Guid Id { get; set; }
public List<string> items { get; set; }
}
Extensions class:
public static class Helpers
{
public static void safeAdd<T>(this List<T> list, T item)
{
if (list == null)
list = new List<T>();
list.Add(item);
}
}
Part of main:
Test t = new Test();
t.items.safeAdd("testWord");
//Here t.items == null; WHY?
You have only assigned to a local method variable (which exists only inside the extension method) - this doesn't do anything to invoke the set, and to be honest there's no convenient way to get access to both the get and set without being verbose, or using lots of reflection / Expression code. IMO just do it in the class:
private List<string> items;
public List<string> Items { get {
return items ?? (items = new List<string>()); } }
This will automatically initialize and assign the list the first time it is accessed.
It wouldn't be thread-safe unless I sync'd, or (perhaps preferable) used Interocked.CompareExchange for the assign. View Interlocked
it could be made thread-safe easily enough, but this is rarely a requirement for instance methods, and has associated overhead
If you're using .NET 4.0, you can use the Lazy class to automatically handle lazy initialization. Your code then becomes:
private class Test
{
public Test()
{
Id = Guid.NewGuid();
//items = new List<string>();
}
public Guid Id { get; set; }
private Lazy<List<string>> _items = new Lazy<List<string>>();
public List<string> items
{
get { return _items.Value; }
}
}
You can then call Test.items.Add at any time. It will be initialized on first use.
See Lazy Initialization for more information.
An more compact way using new C# features
private List<string> _items;
public List<string> Items
{
get => _items ??= new();
set => _items = value;
}
I have a client-server application, parts of which "talk" to each other through WCF (netTcp binding).
I have my DataContract, which has 1 field of a 3rd party class:
[Serializable]
public class MyResult{
public ThirdPartyResult Result {get;set;}
/* other fields */
}
Using reflection i see this:
[Serializable]
public class ThirdPartyResult {
private IList result;
public IList Result
{
get { return result ?? (result = new ArrayList());}
}
}
When calling the server from client I have the result as ArrayList on server. After it comes to client the result field becomes a fixed size array.
I didn't use Add service reference, but i use assembly sharing and just do
ChannelFactory<IMyContract>.CreateChannel(new NetTcpBinding("Configuration.Name"), address);
UPDATE: the service contract
[ServiceContract]
[ServiceKnownType(typeof(ArrayList))]
[ServiceKnownType(typeof(ThirdPartyResult))]
public interface IMyContract
{
MyResult GetResult();
}
Now the question:
How can I tell WCF to use ArrayList instead of Array?
I came up with a very bad solution (from my point of view)
Generally I wanted an ArrayList to be preserved to be able to add items to it. Finally I came up with the solution below. Yes, I know, this is completely bad, and that's why I'm still looking for some better variant.
if (thirdParty.Results != null && thirdParty.Results.IsFixedSize)
{
var results = new ArrayList(thirdParty.Results);
// Finding result by ReferenceEquals to not be tight to private variable name
var resultsField = thirdParty.GetType()
.GetFields(BindingFlags.Default | BindingFlags.Instance | BindingFlags.NonPublic)
.Where(f => ReferenceEquals(f.GetValue(thirdParty), thirdParty.Results))
.FirstOrDefault();
if (resultsField != null)
resultsField.SetValue(thirdParty, results);
}
thirdParty.AddResult(otherChild);
When you create a new Service Reference (or configuring an existing reference) in the Visual Studio there is a property something like "Deserialize arrays as" and there you can choose array/list/etc. You could take a look at the generated code and change your code to achieve what you want.
Please see the following:
WCF: Serializing and Deserializing generic collections
This solved my problem: Both the private member and custom property method work for me.
[DataMember]
private List<Person> members = new List<Person>();
OR change the property to:
[DataMember]
private Iist<Person> members = new Iist<Person>();
[DataMember()]
public IList<Person> Feedback {
get { return m_Feedback; }
set {
if ((value != null)) {
m_Feedback = new List<Person>(value);
} else {
m_Feedback = new List<Person>();
}
}
}
Ultimately your contract contains no information that would make it choose any particular implementation. The best way to fix this would be; to make result well-typed, perhaps as ArrayList:
private ArrayList result;
public IList Result {
get { return result ?? (result = new ArrayList());}
}
personally I'd hope to see a List<T> with [DataContract]/[DataMember] etc, but...
if nothing else then I would write an extension class to extend ThirdPartyResult
public static class ThirdPartyResultExtension
{
public static ArrayList ResultsAsArrayList(this ThirdPartyResult d)
{
ArrayList list = new ArrayList();
list.AddRange(d.Result);
return list;
}
}
public class ThirdPartyResult
{
private IList result;
public IList Result
{
get { return result ?? (result = new ArrayList()); }
}
}
and use it like
ThirdPartyResult r;
ArrayList arrlist = r.ResultsAsArrayList();
Is it possible to do somethink like
public class TestClass
{
public List<double> preTvoltage
{
get
{
return preTvoltage;
}
set
{
preTvoltage.Add(this); //how to add to the List??
}
}
}
The reason I want to do this (I do not know if this is a best method, just as far as my knowledge allows) because I have to get data from xml files that do not have always same number of data in them.
Later I want to fill a ListView rows and using list I can count how many items are and how many columns will be needed.
Here is a schematic of xml file:
and there are also Trigger and PostTrigger nodes in xml file with same data sorting.
and here is the listview I want to achive:
Link to full size image
So, there are some pin groups and each pingroup has lots of data, the above code I gave, was just to hold 1 of the voltage nodes in xml file.
I am pretty much listening for your ideas!
Thanks.
No, and it defies usage of properties - you should implement it as an Add (or similarly aptly named) method.
You can't add this, because this is a TestClass, not a double; and you can't add value, as otherwise suggested, because that is a List<double>, and Add requires a double.
It's not clear how you would use this, but it looks like a very bad idea to me. Setting a collection as a property is slightly unusual already, but it's even odder for that set operation to mutate the list. It's additionally weird that you're not using the value variable within the setter... why not?
You should consider what the calling code would look like, and whether that's really the clearest way of expressing the semantics you want.
set { preTvoltage.AddRange(value); }
As Jon Skeet is saying, this is not what you should do. Instead, do
TestClass t = new TestClass();
t.PreTvoltage.Add(...);
declaring the property as
public List<double> PreTvoltage
{
get { return preTvoltage; }
}
The type of a getter and setter must match.
You could have:
public List<double> preTvoltage
{
get
{
return preTvoltage;
}
set
{
preTvoltage.AddRange(value); //add all items in list assigned.
}
}
However, this seems like a bad idea as it would be confusing to users why the value got did not match the value just set. I would have the two operations as separate members, and the setter either not exist or else overwrite the existing preTvoltage entirely.
You can not implement it like this, the preferable way is to make collection controls like:
private IList<double> _preTvoltage = new List<double>();
public IEnumerable<double> preTvoltage
{
get
{
return preTvoltage.AsEnumerable();
}
}
public void AddTvoltage(double item)
{
_preTvoltage.Add(item);
}
Well I managed to solve my problem this way:
public class ITestData
{
public string pinName { get; set; } //Name of the pin
public double stressLevel { get; set; } //Stress level for latchup
public int psuCount { get; set;} //Number of PSU's
public List<double[]> preTrigger = new List<double[]>();
public List<double[]> inTrigger = new List<double[]>();
public List<double[]> postTrigger = new List<double[]>();
public void AddPreTrigger(double volt, double curr)
{
double[] data = new double[2];
data[0] = volt;
data[1] = curr;
preTrigger.Add(data);
}
public void AddInTrigger(double volt, double curr)
{
double[] data = new double[2];
data[0] = volt;
data[1] = curr;
inTrigger.Add(data);
}
public void AddPostTrigger(double volt, double curr)
{
double[] data = new double[2];
data[0] = volt;
data[1] = curr;
postTrigger.Add(data);
}
}