Fields vs. Properties and XMLSerializers (101) - c#

So I've been studying the use of various Serializers in the .NET Framework and while trying to experiment on preventing certain objects in a class from being serialized I was thrusted back to some very basic programming questions that I "thought" I knew. Given this example:
public class Example
{
public string examName;
[XmlIgnore]
public int exampleNumber;
public Example()
{ }
[XmlIgnore]
public int ExampleNumberTwo { get; set; }
}
I can create an instance of this class and using the XMLSerializer can output the content of this class in XML format. The [XmlIgnore] attribute actually does what I'd expected; it prevents the serialization of the referenced items.
So venturing further I replaced the [XmlIgnore] declaration for "exampleNumber" with [NonSerializable] expecting the similar results but the output did not change. After searching through resources, it was stated that the [NonSerializable] attribute should only be used on fields and [XmlIgnore] attributes should be used on properties.
Yet another post stated that the [NonSerializable] attribute has no effect when using the XMLSerializer but will produce the expected results when using the SOAP or BinaryFormatter. So I'm lost on the concept at this point.
But this brought me to the basic question, what defines a field vs. a property? I know its a basic question and I've even viewed other discussions here but the degree of clarity I am looking for still wasn't really clear.
I can use the [XmlIgnore] attribute on the property (ExampleNumberTwo) or the variable (exampleNumber) so the statement that it can ONLY be used on Properties doesn't seem correct.
But then again, I have always referred to the objects in my example such as (examName) and (exampleNumber) as being member variables. So what exactly is the signature of a "Field"
Can anyone shed some light on this?

The MSDN documentation supports the idea that [NonSerialized] only gives the expected results with the binary and SOAP serializers:
When using the BinaryFormatter or SoapFormatter classes to serialize
an object, use the NonSerializedAttribute attribute to prevent a field
from being serialized. For example, you can use this attribute to
prevent the serialization of sensitive data.
The target objects for the NonSerializedAttribute attribute are public
and private fields of a serializable class. By default, classes are
not serializable unless they are marked with SerializableAttribute.
During the serialization process all the public and private fields of
a class are serialized by default. Fields marked with
NonSerializedAttribute are excluded during serialization. If you are
using the XmlSerializer class to serialize an object, use the
XmlIgnoreAttribute class to get the same functionality. Alternatively,
implement the ISerializable interface to explicitly control the
serialization process. Note that classes that implement ISerializable
must still be marked with SerializableAttribute.
In terms of "field" vs. "property", fields are straight data variables contained by a class. Properties are actually specially named methods on the class (get_PropName() and set_PropName()). In your code, the compiler allows you to use properties the same way you would use a field, and then inserts the appropriate get/set call for you.
Oftentimes, properties will be simple wrappers around a field:
private int myField;
public int MyProperty
{
get { return myField; }
set { myField = value; }
}
But they don't have to be:
public int TodaysDate
{
get { return DateTime.Today; }
}
In general, you want all your fields to be private, since they're supposed to be implementation details. Any simple data that you'd like to expose should be done via a property, since you can easily surround the data access with (changeable) logic.

In C#, the short answer is that properties have get and/or set methods, while fields do not. VB.NET makes it a little more evident by requiring the "Property" qualifier to be used to differentiate one.
With C#, you can just append " { get; set; }" to the end of a field's definition and it's now a property.
Where this really comes into play is in reflection. Fields and Properties are segregated from one another into different enumerable collections.

This answer to What are the differences between the XmlSerializer and BinaryFormatter will help you get started in the right direction.

Related

DataContract secret behavior?

Every time I meet this attribute, I always see such usage:
[DataContract]
class DataTransferObject
{
[DataMember]
public int Value {get;set;}
}
And in this example all inherited members should apply DataMember attribute to every property or field, this can lead to VERY clumsy and poilerplate code. But, recently I found (maybe secret feature?) a very elegant way of using it:
[DataContract]
public abstract class DTOBase
{
}
public class MyDTO : DTOBase
{
public int Value {get;set;}
public MyDTO(){} //important part is here
}
Important part: You should always explicitly define parameterless constructor, otherwise it won't serialize properly.
And yeah. It will serialize all its public members, no matter how deep will be inheritance, without need to apply attributes to members or class definitions.
Is this somehow documented somewhere (I didn't found)? Because, I were very supprized how much of boilerplate can be avoided.
Actually, you don't need to use DataContract and DataMember attributes if you don't want to, however they give you flexibility in defining what needs to be serialized and how.
I suggest starting with article Serializable Types on MSDN, it has a lot of information how Data Contract serializer works. Here are first 2 paragraphs, proving that you don't need to use attributes:
By default, the DataContractSerializer serializes all publicly visible
types.
All public read/write properties and fields of the type are
serialized. You can change the default behavior by applying the
DataContractAttribute and DataMemberAttribute attributes to the types
and members This feature can be useful in situations in which you have
types that are not under your control and cannot be modified to add
attributes. The DataContractSerializer recognizes such "unmarked"
types.
The main rules that apply to your case are:
DataContract attribute is not inherited. You can either apply it or not on your base class DTOBase, it is ignored in child class MyDTO. You can remove DataContract attribute from DTOBase class and result will be the same.
If you use DataContract attribute on a class, then only members that have DataMember attribute will be serialized. This is what happened in class DataTransferObject in your first sample.
If you do not use DataContract attribute on a class, then all public members of a class are serialized. This is what happened with your class MyDTO.

how to use Protobuf-net for complex objects?

we're using wpf, and would like to serialize a complex object -- a view model.
Using binary formatter, I can just add an attribute [Serializable], and it would automatically work for the entire class, recursively.
Do we have something similar in protobuf?
Also, where is the documentation?
I learned about protoinclude, and protomembers, but these are complex objects that may change.
We want to use protobuf because it is compact, fast, and portable. But I don't rule out other options, if it accomplishes the same goals, more or less, and is easy to use.
Please answer or suggest options. Thank you
BinaryFormatter manages this by including the field name in the output, which is both verbose and brittle (for example, it won't withstand changing something from a field+property to an automatically implemented property).
If you want to do something similar in protobuf-net, you can use "ImplicitFields", however, note that this assigns an integer key to each member alphabetically, so is only suitable if your model is totally fixed as a contract and will not add/rename members as this will break the contract (meaning: you can't deserialize existing data correctly). For example:
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Foo {...} // all public fields and properties are serialized,
// similar to XmlSerializer
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
public class Bar {...} // all fields (not properties; public or private)
// are serialized, similar to BinaryFormatter
If your contract is not totally fixed, it would be preferable to explicitly assign a key to each serialized member, which can be done in a great many ways. The simplest being:
[ProtoContract]
public class Foo {
[ProtoMember(1)]
public int A {get;set;}
...
}

Set DataContract and DataMember Without All the Attributes

I find the [DataContract] and [DataMember] attributes a bit messy and would rather do this with code in a config method or something. Is this possible?
You don't have to use these attributes at all. DataContractSerializer will serialize all public properties with getter and setter but in case of serializing entities with navigation properties you will easily end with exception due to "cyclic reference".
To avoid that exception you must either use [DataContract(IsReference = true)] on your entity class with DataMember on every property you want to serilize or IgnoreDataMember on every property you don't want to serialize.
The last and the most complex option is avoiding attributes completely and custom classes implementing IDataContractSurrogate to control serialization outside of the type.
You can also write your completely custom serialization process or use XML serialization or binary serialization with all its requirements.
No, the DataContractSerializer is an opt-in serializer - you have to tell it what you want included.
With other serializers you need to use things like NonSerializedAttribute or XmlIgnoreAttribute to tell the serializer to leave things alone.
I know this is a rather old post, but I came here thinking the same thing if there is a way to set all member attributes automatically on some legacy code with public fields and no getters and setters.
What makes it look just a little bit less messy is shortening up the name DataMember:
using DM = System.Runtime.Serialization.DataMemberAttribute;
[DataContract]
public class SomeClass
{
[DM] public bool IsMO;
[DM] public string LabCode;
[DM] public string OrderNumber;
}

Set The "NonSerializedAttribute" To An Auto Property

This cannot be done in C#. Any way to do it?
...
laugh, in case my little pun wasn't understood, what I mean is: how can I mark a property in C# as NonSerialized? Of course, when the property contains logic, it's natural to be unable to do it, but Auto-Properties are serializable, and, as such, I would expect to have some way to allow me to prevent their serialization.
[NonSerialized]
public string MyProperty { get; set; }
Is an error
[XmlIgnore]
public string MyProperty { get; set; }
Is not an error
NonSerialized Indicates that a field of a serializable class should not be serialized.
XmlIgnore Instructs the Serialize method of the XmlSerializer not to serialize the public field or public read/write property value
so, if you ask
I would expect to have some way to allow me to prevent their serialization.
the answer yes, if you're using XmlSerializer
For events, you can use [field:NonSerialized], but for auto-properties this does not work. It seems like it would be a very logical way to handle auto-properties as well, but for some reason it doesn't seem to have been implemented.
Edit * :
Auto Implemented Properties are backed by an anonymous field which you don't really have access to, attributes are designed to be controlled by a reflection based mechanism. These fields cannot be referenced by the reflection mechanism (because they are anonymous). This compiler feature would require a lot of changes to the generation of auto-properties... It would also require that the compiler treat auto-properties as fields for the purpose of marking field attributes onto them.
To answer the more fundamental part of the question - your point was that Auto-Properties are serialized and so there should be a way to control their serialization. You're right - but auto properties are meant as a shorthand and were never designed to give you the full flexibility, but rather to allow you to easily extend their functionality the "long" way if you ever needed it.
I added the more details answer from my comments to the body of the answer.
I theory yes, it's possible. In practical nope, not possible.
Serialization classes only works on private fields. When you define a auto property; at behind the scenes compiler automatically generates a private field for it. That means this is a language feature not a .net framework feature.
Also serialization classes are included in redbits, which is any change prohibited due compatibility except bug fixes.
I hope thats helps.
What was said above is right: You can't prevent an auto-implemented property from being serialized by setting an attribute like [NonSerialized]. It just does not work.
But what does work is the [IgnoreDataMember] attribute in case you are working with an WCF [DataContract]. So
[DataContract]
public class MyClass
{
[DataMember]
public string ID { get; set; }
[IgnoreDataMember]
public string MySecret { get; set; }
}
will get serialized under WCF.
Although since WCF is an opt-in technology, you can also just omit the [IgnoreDataMember] and it will work as well. So maybe my comment is a little academical ;-)
You could probably do this with Mono.Cecil, a bytecode manipulation library. Theoretically, you could add custom attributes to the hidden backing field. This is so inconvenient, however, that I don't think it warrants an example.
If you had a large application with your own postprocessor, you might consider creating your own substitute for NonSerializedAttribute that could be applied to properties. The postprocessor could then use Mono.Cecil or similar to apply NonSerializedAttribute to the backing fields. It's quite common for large applications to undergo such postprocessing to save that extra bit of typing.
[NonSerialized] public decimal yourproperty;
(decimal as example.)
Also remember, if you want enable your class to initialize a nonserialized member automatically, use the IDeserializationCallback interface and then implement IDeserializationCallback.OnDeserialization.

How do attribute classes work?

My searches keep turning up only guides explaining how to use and apply attributes to a class. I want to learn how to create my own attribute classes and the mechanics of how they work.
How are attribute classes instantiated? Are they instantiated when the class they are applied to is instantiated? Is one instantiated for each class instantiated that it is applied to? E.g. if I apply the SerializableAttribute class to a MyData class, and I instantiate 5 MyData instances, will there be 5 instances of the SerializbleAttribute class created behind the scenes? Or is there just one instance shared between all of them?
How do attribute class instances access the class they are associated with? How does a SerializableAttribute class access the class it is applied to so that it can serialize it's data? Does it have some sort of SerializableAttribute.ThisIsTheInstanceIAmAppliedTo property? :) Or does it work in the reverse direction that whenever I serialize something, the Serialize function I pass the MyClass instance to will reflectively go through the Attributes and find the SerialiableAttribute instance?
I haven't use attributes in my day-to-day work before, but I have read about them.
Also I have done some tests, to back up what I'll say here. If I'm wrong in any place - feel free to tell me this :)
From what I know, attributes are not acting as regular classes. They aren't instantiated when you create an object that they are applied to, not one static instance, not 1 per each instance of the object.
Neither do they access the class that they are applied to..
Instead they act like properties (attributes? :P ) of the class. Not like the .NET class properties, more like in the "one property of glass is transparency" kind of property. You can check which attributes are applied to a class from reflection, and then act on it accordingly. They are essentially metadata that is attached to the class definition, not the objects of that type.
You can try to get the list of attributes on a class, method, property, etc etc.. When you get the list of these attributes - this is where they will be instantiated. Then you can act on the data within these attributes.
E.g. the Linq tables, properties have attributes on them that define which table/column they refer to. But these classes don't use these attributes. Instead, the DataContext will check the attributes of these objects when it will convert linq expression trees to SQL code.
Now for some real examples.. I've ran these in LinqPad, so don't worry about the strange Dump() method. I've replaced it with Console.WriteLine to make the code easier to understand for the people who don't know about it :)
void Main()
{
Console.WriteLine("before class constructor");
var test = new TestClass();
Console.WriteLine("after class constructor");
var attrs = Attribute.GetCustomAttributes(test.GetType()).Dump();
foreach(var attr in attrs)
if (attr is TestClassAttribute)
Console.WriteLine(attr.ToString());
}
public class TestClassAttribute : Attribute
{
public TestClassAttribute()
{
DefaultDescription = "hello";
Console.WriteLine("I am here. I'm the attribute constructor!");
}
public String CustomDescription {get;set;}
public String DefaultDescription{get;set;}
public override String ToString()
{
return String.Format("Custom: {0}; Default: {1}", CustomDescription, DefaultDescription);
}
}
[Serializable]
[TestClass(CustomDescription="custm")]
public class TestClass
{
public int Foo {get;set;}
}
The console result of this method is:
before class constructor
after class constructor
I am here. I'm the attribute constructor!
Custom: custm; Default: hello
And the Attribute.GetCustomAttributes(test.GetType()) returns this array:
(the table shows all available columns for all entries.. So no, the Serializable attribute does not have these properties :) )
Got any more questions? Feel free to ask!
UPD:
I've seen you ask a question: why use them?
As an example I'll tell you about the XML-RPC.NET library.
You create your XML-RPC service class, with methods that will represent the xml-rpc methods. The main thing right now is: in XmlRpc the method names can have some special characters, like dots. So, you can have a flexlabs.ProcessTask() xml rpc method.
You would define this class as follows:
[XmlRpcMethod("flexlabs.ProcessTask")]
public int ProcessTask_MyCustomName_BecauseILikeIt();
This allows me to name the method in the way I like it, while still using the public name as it has to be.
Attributes are essentially meta data that can be attached to various pieces of your code. This meta data can then be interogate and affect the behaviour of certain opperations.
Attributes can be applied to almost every aspect of your code. For example, attributes can be associated at the Assembly level, like the AssemblyVersion and AssemblyFileVersion attributes, which govern the version numbers associated with the assembly.
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Then the Serializable attribute for example can be applied to a type declaration to flag the type as supporting serialization. In fact this attribute has special meaning within the CLR and is actually stored as a special directive directly on the type in the IL, this is optimized to be stored as a bit flag which can be processed much more efficiently, there are a few attributes on this nature, which are known as pseudo custom attributes.
Still other attributes can be applied to methods, properties, fields, enums, return values etc. You can get an idea of the possible targets an attribute can be applied to by looking at this link
http://msdn.microsoft.com/en-us/library/system.attributetargets(VS.90).aspx
Further to this, you can define your own custom attributes which can then be applied to the applicable targets that your attributes are intended for. Then at runtime your code could reflect on the values contained in the custom attributes and take appropriate actions.
For a rather naive example, and this is just for the sake of example :)
You might want to write a persistence engine that will automatically map Classes to tables in your database and map the properties of the Class to table columns. You could start with defining two custom attributes
TableMappingAttribute
ColumnMappingAttribute
Which you can then apply to your classes, as an example we have a Person class
[TableMapping("People")]
public class Person
{
[ColumnMapping("fname")]
public string FirstName {get; set;}
[ColumnMapping("lname")]
public string LastName {get; set;}
}
When this compiles, other than the fact that the compiler emits the additional meta data defined by the custom attributes, little else is impacted. However you can now write a PersistanceManager that can dynamically inspect the attributes of an instance of the Person class and insert the data into the People table, mapping the data in the FirstName property to the fname column and the LastName property to the lname column.
As to your question regarding the instances of the attributes, the instance of the attribute is not created for each instance of your Class. All instances of People will share the same instance of the TableMappingAttribute and ColumnMappingAttributes. In fact, the attribute instances are only created when you actually query for the attributes the first time.
Yes they're instantiated with the parameters you give it.
The attribute does not "access" the class. The attribute is attached to the class' / property's attribute list in the reflection data.
[Serializable]
public class MyFancyClass
{ ... }
// Somewhere Else:
public void function()
{
Type t = typeof(MyFancyClass);
var attributes = t.GetCustomAttributes(true);
if (attributes.Count(p => p is SerializableAttribute) > 0)
{
// This class is serializable, let's do something with it!
}
}
Think of attributes are post-its that are attached to the classes or method definitions (embedded in the assembly metadata).
You can then have a processor/runner/inspector module that accepts these types by reflecting, looks for these post-its and handles them differently. This is called declarative programming. You declare some behavior instead of writing code for them in the type.
Serializable attribute on a type declares that it is built to be serialized. The XmlSerializer can then accept an object of this class and do the needful. You mark the methods that need to be serialized/hidden with the right post-its.
another example would the NUnit. The NUnit runner looks at the [TestFixture] attributes all classes defined in the target assembly to identify test classes. It then looks for methods marked with [Test] attribute to identify the tests, which it then runs and displays the results.
You may want to run through this tutorial at MSDN which has most of your questions answered along with an example at the end. Although they could have extracted a method called
Audit(Type anyType); instead of duplicating that code. The example 'prints information' by inspecting attributes.. but you could do anything in the same vein.
If you take an eye out this downloadable open source code LINQ to Active Directory (CodePlex), you might find interesting the mechanism of the Attributes.cs file where Bart De Smet has written all of his attributes classes definitions. I have learned attributes there.
In short, you may specialize the Attribute class and code some specialized properties for your needs.
public class MyOwnAttributeClass : Attribute {
public MyOwnAttributeClass() {
}
public MyOwnAttributeClass(string myName) {
MyName = myName;
}
public string MyName { get; set; }
}
and then, you may use it wherever MyOwnAttributeClass gets useful. It might either be over a class definition or a property definition.
[MyOwnAttributeClass("MyCustomerName")]
public class Customer {
[MyOwnAttributeClass("MyCustomerNameProperty")]
public string CustomerName { get; set; }
}
Then, you can get it through reflection like so:
Attribute[] attributes = typeof(Customer).GetCustomAttribute(typeof(MyOwnAttributeClass));
Consider that the attribute you put between square brackets is always the constructor of your attribute. So, if you want to have a parameterized attribute, you need to code your constructor as such.
This code is provided as is, and may not compile. Its purpose is to give you an idea on how it works.
Indeed, you generally want to have a different attribute class for a class than for a property.
Hope this helps!
Not much time to give you a fuller answer, but you can find the Attributes that have been applied to a value using Reflection. As for creating them, you inherit from the Attribute Class and work from there - and the values that you supply with an attribute are passed to the Attribute class's constructor.
It's been a while, as you might be able to tell...
Martin

Categories

Resources