The external data is recognized as the data we must pull or push from outside of a boundary of the process hosting the computer program. In general, the external data may be grouped as follows.
- streaming: bitstreams managed using the content of files, or network payload
- structural: data fetched/pushed from/to external database management systems using queries
- graphical: data rendered on a Graphical User Interface (GUI)
This article collects a description of examples explaining the selected aspects of the streaming data usage sent over a network or managed as files (see also External Data - File and Stream Concepts). Here the first problem arises, namely to save/read working data, we need a transition operation in both directions between streaming and object-oriented data regardless of the types we used to create the graph of objects contained in the working memory. This transition from the object world to the streaming world is called serialization. Deserialization is the reverse process, which involves replacing the bitstream with interconnected objects located in the working memory of a computer. Reflection used to implement serialization/deserialization usually employs attributes to profile the behavior of this functionality. In this article, selected examples related to the definition and usage of attributes are explained.
It is the next part of a series of articles commonly titled Programming in Practice - External Data.
Of course, attributes are not only used for this particular application. By design, the described code examples are intentionally limited to have educational applicability.
Profiling Development Environment
Let's start by creating a very simple AttributedClass example used as a starting point for the discussion on attributes. It has only one method, but its functionality is not important in the context of the discussion. The method creates an object and returns it. Imagine that after some time, we conclude that this method is not perfectly correct anymore, and we want to avoid referencing it. We know it is used in many places in the program, so to preserve backward compatibility, we cannot simply remove it from the program text to avoid triggering a bunch of syntax errors. Hence, we must keep in place this definition, but we should associate additional information with code in a declarative way. This additional information should prevent it from being used in the program any further. This way, we try to fix an issue by preventing referencing of inadequate code instead of replacing it. In other words, there will be no further references to it in new programs.
We may use the Obsolete
attribute for this purpose. To observe this attribute and the effects it causes, let's open a test window and add a test method. In the test method, we simply call the method that we previously marked with the Obsolete
attribute, and we see that the compiler now reports a warning. It is also available in the error list. Therefore, this is a clear signal that we should not use this method because it is no longer valid.
This warning should make us use some other alternative solutions. Of course, we could use a regular comment instead. Unfortunately, this will cause us to lose the warning to avoid using this method in newly created program fragments. Based on this, we can conclude that a comment is a very good tool for communicating with the reader of the program text - after all, any program is a text. On the other hand, attributes are a concept for communicating with the compiler. And as we will see next, not only with the compiler.