I am passing a classobject(Cache class object) as a reference in a constructor of Myclass.
public class Test{
static void Main(string[] args){
Cache<string, string> cache;
Myclass obj = new MyClass(ref cache);
obj.doSomething();
Console.WriteLine(cache.key); // I want this value to get changed according to the doSomething Method
Console.WriteLine(cache.value);// I want this value to get changed according to the doSomething Method
}
}
Now in MyClass, I want to set the value of this cache
public class Myclass{
ref Cache<string, string> C;
Myclass(ref Cache<string, string> cache){
this.C = cache;
}
void doSomething(){
C.key = "key";
C.value = "value"
}
}
I want that changing the value of cache in Myclass should reflect in Test Class. But I am not sure how to achieve this. Any help would be appreciated.
Here is the complete scenario which I am trying to do. We have a no of multiple orgs and there are some properties of the org which are same for some org and we don't want to compute those property again and again as it is costly operation. That properties are computed in doSomethingMethod above.
My cache is actually a list. And this cache variable will be passed in the multiple orgs. So in dosomething method I want to check whether the cache is being set or not by any other org and if the key is present I will not compute operation and I will just return from cache.
If you omit the ref keyword, what you give to the constructor is a reference to the cache instance. The reference itself will be a copy, but still reference the same instance. If you then change properties of said instance, it will reflect through all other references to the same instance.
Consider this example:
using System;
public class Program
{
public static void Main()
{
MyCache sharedCache = new MyCache();
Department dpt1 = new Department(sharedCache);
Department dpt2 = new Department(sharedCache);
Console.WriteLine($"Dpt1: {dpt1.CacheValue}");
Console.WriteLine($"Dpt2: {dpt2.CacheValue}");
sharedCache.Value = 1;
Console.WriteLine($"Dpt1: {dpt1.CacheValue}");
Console.WriteLine($"Dpt2: {dpt2.CacheValue}");
dpt1.ChangeValue(2);
Console.WriteLine($"Dpt1: {dpt1.CacheValue}");
Console.WriteLine($"Dpt2: {dpt2.CacheValue}");
}
}
public class Department
{
private readonly MyCache cache;
public Department(MyCache cache)
{
this.cache = cache;
}
public int CacheValue => this.cache.Value;
public void ChangeValue(int newValue)
{
this.cache.Value = newValue;
}
}
public class MyCache
{
public int Value {get; set;} = default;
}
Output:
Dpt1: 0
Dpt2: 0
Dpt1: 1
Dpt2: 1
Dpt1: 2
Dpt2: 2
Related
I have a record definition where I would like to only check equality on public/specific member variables in the record definition. I haven't found a way to do this without making a custom Equals function and I would prefer not to that if there is another nicer solution. Any reflections on whether private member variables in records is a bad pattern or not, is also appreciated.
Example of record where equality is true:
public record Test
{
public string Variable { get; init; }
public Test(string someValue)
{
Variable = someValue;
}
}
[Fact]
public void RecordTest()
{
var test1 = new Test("hello");
var test2 = new Test("hello");
Assert.Equal(test1, test2); // Passes
}
Example of record where I would like it to be true, but it's not:
public record Test
{
// I believe this is causing it to fail, can it be ignored somehow?
private readonly List<string> _list = new();
public string Variable { get; init; }
public Test(string someValue)
{
Variable = someValue;
_list.Add(someValue);
}
}
[Fact]
public void RecordTest()
{
var test1 = new Test("hello");
var test2 = new Test("hello");
Assert.Equal(test1, test2); // Fails
}
In the microsoft documentation you can read this:
For records, value equality means that two variables of a record type
are equal if the types match and all property and field values match.
For other reference types such as classes, equality means reference
equality. That is, two variables of a class type are equal if they
refer to the same object. Methods and operators that determine
equality of two record instances use value equality.
The list here needs to have the same reference for the equality to work.
I think using an equality comparer or override equal is the best way to go.
What about creating your own class that wraps your list, and implement your own object Equals and GetHashCode overrides, as well as implementing IEquatable interface. Then use your own wrapper in the record. Something like:
public class ListWrapper : IEquatable<ListWrapper>
{
private readonly List<string> _list = new();
public void Add(string item) => _list.Add(item);
public bool Equals(ListWrapper other)
{
return _list.SequenceEqual(other._list);
}
// you may or may not want to override object Equals and GetHashCode.
}
public record Test
{
private readonly ListWrapper _list = new();
public string Variable { get; init; }
public Test(string someValue)
{
Variable = someValue;
_list.Add(someValue);
}
}
I played around with the ValueTuple structure and tried to implement an immutable composite key. The key is composed of value types.
I tried to break the following implementation with some unit tests, so far without success. Am I missing something?
Also this is just out of curiosity, I want to get to ValueTuples and it's limitations before the release of .NET 4.7.
So far my understanding of a ValueTuple is that it is only mutable as a variable but not as a field or property. Not sure what "mutable" means here though. Does altering a ValueTuple instance actually create a new ValueTuple (like it's common knowledge that strings are "immutable" but actually reference types)?
from this answer
System.ValueTuple isn't only a struct, it's a mutable one, and one has to be careful when using them as such. Think what happens when a class holds a System.ValueTuple as a field.
Here my implementation and tests
public interface IHaveCompositeKey
{
(Guid id, string name) Key { get; }
}
public class ImmutableKey : IHaveCompositeKey
{
public (Guid id, string name) Key { get; }
public ImmutableKey((Guid id, string name) key) => Key = key;
public override int GetHashCode() => Key.GetHashCode();
public override bool Equals(object obj)
{
var a = obj as ImmutableKey;
return a != null && Key.Equals(a.Key);
}
}
[TestFixture]
public class KeyTests
{
[Test]
public void Test1() // passes
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
var b = new ImmutableKey(key);
Assert.IsTrue(a.Equals(b));
Assert.IsTrue(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test2() // passes
{
(Guid id, string name) key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
key.name = "Bar"; // mutable
var b = new ImmutableKey(key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
[Test]
public void Test3() // does not compile
{
var key = (Guid.NewGuid(), "Foo");
var a = new ImmutableKey(key);
// compilation error
a.Key.name = "Bar"; // immutable
var b = new ImmutableKey(a.Key);
Assert.IsFalse(a.Equals(b));
Assert.IsFalse(a.GetHashCode().Equals(b.GetHashCode()));
}
}
error: Cannot modify the return value of 'ImmutableKey.Key' because it is not a variable
There are three cases when one can change mutable struct and see result:
local variable: MyStruct s = new MyStruct(); s.Prop = 4;
field of another type: class MyType { public MyStruct S;} ... myType.S.Prop = 4;
element of array: MyStruct[] myArray =...; myArray[3].Prop = 4;.
Why code in the post did not detect change - code used property and not a field.
Note that List<MyStruct> does not allow modification because indexer (this[..]) returns copy of an item (as there is no support returning reference like C++ does).
I have the following object
var filters = new List<IReportFilter>
{
new ReportFilter
{
ReportColumn = new ReportColumn{ ColumnKey = "Result.IsCompleted"},
Value = "1",
SubFilters = new List<IReportFilter>
{
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Alhayek"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ ColumnKey = "User.LastName"}, Value = "Smith"},
new ReportFilter { SqlOperator = FilterOperator.Or, ReportColumn = new ReportColumn{ AggregateFunction = SqlAggregateFunctions.Count}, Type = FilterType.GreaterThenOrEqualTo ,Value = "0" },
}
},
};
The obove object is passed to another class using a method like so
IReportModel ReportModel = Template.CreateReport();
ReportModel.Get(filters);
Inside the the Get method of the ReportModel class I want to loop through the filters list and create a new list without changing the original list. the new list will become a subset of the original.
From with in my Get method here is what I have done
public SqlCommand Build(List<IReportFilter> filters)
{
var a = CloneFilters(filters);
var b = CloneFilters(filters);
List<IReportFilter> standardFilters = ExtractFiltersByAType(a, true);
List<IReportFilter> aggregateFilter = ExtractFiltersByAType(b, false);
}
But every time I execute the method ExtractFiltersByAType the value of a,b, and filters change to equal the same value of aggregateFilter.
I am NOT expecting for any of the variables to change. But they are for some reason that I don't understand.
Here is my CloneFilters method
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter);
}
return copyOfFilters;
}
And here is my ExtractFiltersByAType
private List<IReportFilter> ExtractFiltersByAType(List<IReportFilter> filtersSource, bool IsStandard = true)
{
List<IReportFilter> validFilters = new List<IReportFilter>();
foreach (var filterSource in filtersSource)
{
if (filterSource.SubFilters != null && filterSource.SubFilters.Any())
{
filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard); //I think this what could be causing this problem
}
if ((IsStandard && !filterSource.ReportColumn.IsAggregate) || (!IsStandard && filterSource.ReportColumn.IsAggregate))
{
validFilters.Add(filterSource);
}
}
return validFilters;
}
Question
Since I am not using ref to pass the object by reference to the method, why is my function changing the value to original object?
When passing a list of object to method in c#, will the system create a copy or will it passes the object by reference?
How can I solve this problem so that every time I execute ExtractFiltersByAType method, only the copy is changed not the originals?
I am thinking that the line filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard); in the ExtractFiltersByAType is causing the problem but I don't understand why and how.
Without ref
When you pass a reference type as an argument (which includes a list), you pass a copy of the reference to that object. This means you can change your object attributes, but can't change the object itself.
Example:
public class Program
{
static void Main(string[] args)
{
Foo foo = new Foo(1);
Console.WriteLine(foo.Bar);
// This will change foo.Bar
ChangeFoo(foo, 5);
Console.WriteLine(foo.Bar);
// Does not change foo
DoesNotChangeFoo(foo, 10);
Console.WriteLine(foo.Bar);
Console.Read();
}
static void ChangeFoo(Foo foo, int newValue)
{
// Since it receives a copy of the reference to Foo, it actually changes foo.Bar value
foo.Bar = newValue;
}
static void DoesNotChangeFoo(Foo foo, int newValue)
{
// Since it receives a copy of the reference to foo, it only updates this method's reference, not changing the caller's reference
foo = new Foo(newValue);
}
}
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
public int Bar { get; set; }
}
With ref
If you wanted to change the caller's object reference, you would need to pass the actual reference used by the calle's, that's when you use the ref keyword.
Example:
public class Program
{
static void Main(string[] args)
{
Foo foo = new Foo(1);
Console.WriteLine(foo.Bar);
// This will change foo's object reference
ChangeFooObjectReference(ref foo, 15);
Console.WriteLine(foo.Bar);
Console.Read();
}
static void ChangeFooObjectReference(ref Foo foo, int newValue)
{
// SInce you are receiving the actual reference used by the caller, you actually change it's own reference
foo = new Foo(newValue);
}
}
public class Foo
{
public Foo(int bar)
{
Bar = bar;
}
public int Bar { get; set; }
}
Your case
As you correcly assumed, the main cause of your problem is this line:
filterSource.SubFilters = ExtractFiltersByAType(filterSource.SubFilters, IsStandard);
This line actually changes this object's SubFilters.
But it's worth noting that you may have some bigger problems in you Clone method.
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter);
}
return copyOfFilters;
}
This method return's a new List, but the content of that list is exactly the same as the argument's. This means that, if you change any of the object's contained in the object used as an argument, you change it in the new List too.
Here's an example of what's happening.
static void Main(string[] args)
{
List<Foo> foos = new List<Foo>();
foos.Add(new Foo(2));
List<Foo> newFoo = CreateNewFoo(foos);
Console.WriteLine(newFoo.First().Bar);
foos.First().Bar = 5;
// Since we changed the first object of the old list, and it is the same object in the new list, we will get the new result.
Console.WriteLine(newFoo.First().Bar);
Console.Read();
}
static List<Foo> CreateNewFoo(List<Foo> foos)
{
List<Foo> newFoos = new List<Foo>();
foreach(Foo foo in foos)
{
newFoos.Add(foo);
}
return newFoos;
}
I would suggest implementing the ICloneable interface in your IReportFilter interface, and each concrete class implementing IReportFilter.
ICloneable implements a single method Clone(), which returns an object. This method should create a new instance of the same class in which it's implemented, containing a new object identical to the current object. Than you would change your method to:
private List<IReportFilter> CloneFilters(List<IReportFilter> myFilters)
{
List<IReportFilter> copyOfFilters = new List<IReportFilter>();
foreach (var myFilter in myFilters)
{
copyOfFilters.Add(myFilter.Clone() as IReportFilter);
}
return copyOfFilters;
}
As for implementing the ICloneable inteface, refer to this question:
Proper way to implement ICloneable
Edit
As mentioned by user muratgu in the question comments, your CloneFilter method is doing a shallow copy of your list, what you are looking for is a deep copy. That could be implemented with the aforementioned ICloneable interface.
The only thing that ref does is determine whether the method receiving the parameter can modify the variable passed to it. In the case of an object, that means setting the variable to a different object or setting it to null.
But even if you don't use ref, the method you pass the parameter to can can set its properties or call methods which modify the state of that object. That's normal and expected. When you pass an object to another method, it's not just so that the other method can read its properties. You might also want that method to operate on that object in some way that modifies it.
The simplest example is a List<T>. If you pass a List<string> to another method - without using ref - that other method can add items to the list, modify items in the list, clear the list, etc.
The only difference with using ref is that if the method you pass the variable to sets the variable to a different list or sets it to null, it's going to modify the variable in the method that passed the argument.
Most of the time we don't want a method we call to completely replace the variable we pass in. If we wanted a new object we'd write a function that returns an object, not one that replaces the variable we passed in.
There is a very easy trick which creates a dictionary-like structure where keys are types.
The structure acts like a Dictionary<Type, T?> where keys are Type objects and values are instances of the corresponding types.
This wonderful structure is as fast as just a variable or array since the "lookup" is only done once by the compiler/JITter and the proper value reference is compiled into your program.
public static class MyDict<T> {
public static T Value { get; set; }
}
You can work with that structure like this:
MyDict<string>.Value = MyDict<int>.Value.ToString();
The problem is that this "dictionary" is global. The only way to create different dictionaries is to create different classes.
How can create a similar (fastest "lookup", no boxing) non-static structure? (Without code generation.)
Simply said: I want to have multiple Dictionary<Type, object>-like objects without lookup costs, casting and boxing.
Here's an approach that extends the method described in the question:
public class TypeDict
{
public T Get<T>()
{
return MyDict<T>.Values[this];
}
public void Set<T>(T value)
{
MyDict<T>.Values[this] = value;
}
private static class MyDict<T>
{
public static Dictionary<TypeDict, T> Values { get; private set; }
static MyDict()
{
Values = new Dictionary<TypeDict, T>();
}
}
}
Now we can use the TypeDict like this:
void X()
{
var a = new TypeDict();
var b = new TypeDict();
a.Set<int>(1);
a.Set<double>(3.14);
a.Set("Hello, world!");
//Note that type inference allows us to omit the type argument
b.Set(10);
b.Set(31.4);
b.Set("Hello, world, times ten!");
Console.WriteLine(a.Get<int>());
Console.WriteLine(a.Get<double>());
Console.WriteLine(a.Get<string>());
Console.WriteLine();
Console.WriteLine(b.Get<int>());
Console.WriteLine(b.Get<double>());
Console.WriteLine(b.Get<string>());
}
Ark-kun is using generics to essentially generate unique types at compile time. With a generic type, any static members are unique to that specific closed generic type. This way it's processed as fast as a standard static member lookup.
The above usage is equivalent to something like this:
public static class MyDict_String
{
public static string Value { get; set; }
}
public static class MyDict_Int32
{
public static int Value { get; set; }
}
MyDict_String.Value = MyDict_Int32.Value.ToString();
AFAIK, types are "static" (in that you can't define more than one that way) so I don't know of a way to cheat around this and maintain the same performance of a statically compiled member lookup.
Your best bet otherwise (I think) is to create a generic instance type that wraps its own dictionary that uses System.Type for its keys and System.Object for its values to which you have to perform boxing/casting when inserting/retrieving values.
EDIT: Here's a simple implementation wrapping a dictionary:
public class MyTypedDict
{
private Dictionary<Type, object> Values = new Dictionary<Type, object>();
public T Get<T>()
{
object untypedValue;
if (Values.TryGetValue(typeof(T), out untypedValue))
return (T)untypedValue;
return default(T);
}
public void Set<T>(T value)
{
Values[typeof(T)] = value;
}
}
Thinking about it more, it might be possible to achieve a more property-like syntax using an ExpandoObject (http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx) through some tomfoolery, but I feel like this would be pretty abusive and I can only assume terribly prone to runtime errors. (plus it would afford you nothing at compile time)
EDITx2: If you really want to have different sets of values, you could nest it within another generic type:
public static class ValueSets<T>
{
public static class MyDict<U>
{
public static U Value { get; set; }
}
}
With usage like:
ValueSets<int>.MyDict<string>.Value = "Hello ";
ValueSets<bool>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<int>.MyDict<string>.Value + ValueSets<bool>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
But then the initial type int and bool in this case become "magical" and without meaning, plus you would need to provide a unique type per distinct set of values you'd like to use. Plus you could not pass it around and modify as an instance variable, rather it'd be statically accessible (so long as you have access to use the type T). So perhaps you could declare minimally visible types that are named with meaning and use those:
internal class MyFirstWords {}
internal class MySecondWords {}
ValueSets<MyFirstWords>.MyDict<string>.Value = "Hello ";
ValueSets<MySecondWords>.MyDict<string>.Value = "World!";
string helloworld = ValueSets<MyFirstWords>.MyDict<string>.Value + ValueSets<MySecondWords>.MyDict<string>.Value;
Console.WriteLine(helloworld);//Hello World!
Regardless, I think this is quite wacky and I wouldn't recommend it.
A more complicated version. Don't know if it's closer:
Define a generic dictionary:
public class MyDictionary<T>
{
Dictionary<string, T> dict;
public MyDictionary()
{
dict = new Dictionary<string, T>();
}
public T this[string name]
{
get
{
if (dict.ContainsKey(name))
return dict[name];
else
return default(T);//or throw
}
set
{
dict[name] = value;
}
}
}
Then a repository to store those dictionaries:
public class MyRepository
{
List<object> repo;
public MyRepository()
{
repo = new List<object>();
}
public void Add<T>(string name, T value)
{
if (!repo.OfType<MyDictionary<T>>().Any())
repo.Add(new MyDictionary<T>());
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
dict[name] = value;
}
public T GetValue<T>(string name)
{
if (!repo.OfType<MyDictionary<T>>().Any())
return default(T);//or throw
else
{
var dict = repo.OfType<MyDictionary<T>>().FirstOrDefault();
return dict[name];
}
}
}
And finally you may use this repository:
MyRepository repo = new MyRepository();
repo.Add("A", 1);
repo.Add("B", 1);
int i = repo.GetValue<int>("A") + repo.GetValue<int>("B");
In this example, there is MyDictionary<T> boxing to object is left.
From the other side, if your are working with some certain types you may not use thie repository class at all. But utilize separate dictionaties.
MyDictionary<int> intDict = new MyDictionary<int>();
intDict["A"] = 1;
intDict["B"] = 2;
int i = intDict["A"] + intDict["B"];
However it's the same as working with
Dictionary<string, int> intDict = new Dictionary<string, int>();
So the MyRepository class may be edited to use Dictionary<string, T> instead of MyDictionary<T>.
#Konstantin's answer made me remember that there is actually a very fast lookup method - array indexing. This crude PoC code shows a variant of the required structure.
public class TypeDictionary {
static int _maxId = 0;
int _id;
static class Store<T>{
internal static List<T> Values = new List<T>();
}
public TypeDictionary() {
_id = _maxId++;
}
public T GetValue<T>() {
return Store<T>.Values[_id];
}
public void SetValue<T>(T value) {
while(Store<T>.Values.Count < _id) {
Store<T>.Values.Add(default(T));
}
Store<T>.Values[_id] = value;
}
}
This code can be used as follows:
var dict1 = new TypeDictionary();
dict1.SetValue("my string");
string result = dict1.GetValue<string>();
The problem with this solution is it's memory usage caused by the repository being not sparse. This also makes first time value setting more expensive.
Try this:
public class MyDictionary
{
List<object> values;
public MyDictionary()
{
values = new List<object>();
}
public T GetValue<T>()
{
return values.OfType<T>().FirstOrDefault();
}
public bool Add<T>(T value)
{
if (values.OfType<T>().Any())
return false;
else
{
values.Add(value);
return true;
}
}
}
and use it:
var md = new MyDictionary();
md.Add("!!!");
string s = md.GetValue<string>();
This class may store up to one value of type T. But there could corner cases with derived classes and interfaces I guess. You may check, if it suits your need, and probably modify it as you need, if it's close to what you need in general.
What you are looking for is impossible in C#. The language does not support a container that could store multiple objects of different types yet provides a look up method that does not involve casting, boxing or unboxing. You could accomplish something like this with macros in C++, or via a language like javascript where the structure of types can be changed at run-time.
The usage case you are describing fits quite closely with the purpose for which ConditionalWeakTable<TKey,TValue> was added to .NET 4.0. For the purpose you describe, you would include such a table in a static generic class, and then for every class object that's supposed to contain a reference to an item of a particular type you would store into that type's table a reference to object that's supposed to contain the item along with either a reference to the item, or else a reference to a simple item-holder object (note that entries in ConditionalWeakTable will evaporate when an object ceases to exist, but are otherwise immutable, so if you want a mutable association you'll need to create an object to hold it).
Building on #phoog's example with #supercat's suggestion
public class TypeDict
{
public T Get<T>() where T : class
{
T value;
InnerDict<T>.Values.TryGetValue(this, out value);
return value;
}
public void Set<T>(T value) where T : class
{
var cwt = InnerDict<T>.Values;
// lock+remove+add https://github.com/dotnet/coreclr/issues/4545
lock (cwt)
{
cwt.Remove(this);
cwt.Add(this, value);
}
}
private static class InnerDict<T> where T : class
{
public static ConditionalWeakTable<TypeDict, T> Values { get; private set; }
static InnerDict()
{
Values = new ConditionalWeakTable<TypeDict, T>();
}
}
}
I have a class, that should support version tolerant serialization
[Serializable]
class A {
[OptionalField]
int a;
[OptionalField]
MyClass b;
[OptionalField]
MyClass c;
}
How can I correct missing fields after deserialization? I guess, I have to use method marked with [OnDeserializing]. But how can I get which of fields was ignored?
Can I configure auto-deserialization to initialize field by default constructor in case of them missing?
Additionally, you can use OnSerializingAttribute and OnSerializedAttribute to set the fields. As the example shows, fields that have been already set will keep their value. Note, however, that this is only the case if the field is set during the OnSerializing event. Fields set during the OnSerialized event will override the serialized value.
EDIT: In this case you can check in your method (decorated with OnSerialized) if the field equals to null and instantiate when necessary. If there is the possibility that this field is never be used and its creation can be deferred, think about hiding the field in question behind a property and instantiate it lazily.
Models.cs:
using System;
using System.Runtime.Serialization;
namespace SerializationExample
{
[Serializable]
public class Model
{
public Model(){
A = new SomeClass();
}
[OptionalField]
public int value;
[OptionalField]
public SomeClass A;
[OptionalField]
public AnotherClass B;
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
B = new AnotherClass("Set during deserializing");
}
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
// Do sth. here after the object has been deserialized
}
public override string ToString()
{
return String.Format("A: {0}\nB: {1}", A, B);
}
}
[Serializable]
public class SomeClass
{
public string Value { get; set; }
public SomeClass()
{
Value = "Default";
}
public override string ToString()
{
return Value;
}
}
[Serializable]
public class AnotherClass
{
public string Value { get; private set; }
public AnotherClass(string v)
{
Value = v;
}
public override string ToString()
{
return Value;
}
}
}
Program.cs:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace SerializationExample
{
class Program
{
static void Main(string[] args)
{
string[] FileNames = new string[] {
#"model1.bin",
#"model2.bin"
};
Stream[] files = new Stream[] {
File.Create(FileNames[0]),
File.Create(FileNames[1])
};
BinaryFormatter bf = new BinaryFormatter();
Model m1 = new Model();
m1.B = new AnotherClass("Set in app");
m1.A.Value = "Set in app";
Model m2 = new Model();
Console.WriteLine("M1:\n{0}\n", m1);
Console.WriteLine("M2:\n{0}\n\n", m2);
bf.Serialize(files[0], m1);
bf.Serialize(files[1], m2);
foreach (var f in files)
f.Seek(0, SeekOrigin.Begin);
m1 = null;
m2 = null;
m1 = (Model)bf.Deserialize(files[0]);
m2 = (Model)bf.Deserialize(files[1]);
Console.WriteLine("M1:\n{0}\n", m1);
Console.WriteLine("M2:\n{0}\n\n", m2);
foreach (var f in files)
f.Close();
}
}
}
Output:
M1:
A: Set in app
B: Set in app
M2:
A: Default
B:
M1:
A: Set in app
B: Set in app
M2:
A: Default
B: Set during deserializing
If you just want to initialize those values to defaults, all you need is a default parameterless constructor that initializes them. This will get called during deserialization, and any missing fields will keep whatever values you initialized them to in the constructor.
If you want more control, you can implement the ISerializable interface and the proper constructor on your class (you should usually do both, though often one or the other is unneeded.)
If C# finds a constructor with the signature:
protected A ( SerializationInfo info, StreamingContext context )
{
}
it will call that constructor, and pass a weakly-typed dictionary with all of the serialization information it has. (You can use ISerializable::GetObjectData to write custom fields into the object and retrieve them in the constructor). You can use the info.GetXXX methods to extract those values.
One thing to note: if you implement this constructor, you have to do all of the work, including the fields that would normally get deserialized automatically. For any missing fields, just set them appropriately. Similarly, if you implement GetObjectData, you have to serialize everything in that method. It's pretty simple, but if you change your class you need to edit your custom method/constructor appropriately.