How to assign ByteSerialize attribute/length as a variable - c#

I'm creating models with different types and length which are used as a request/response to/from an API.
[ByteSerialize(1)]
public string ByteLength { get; set; }
[ByteSerialize()]
public string Byte { get; set; }
I would like first to get the ByteLength that comes from the API and them to pass it to the [ByteSerialize(?)]

Attributes are inert - there's no magic way of getting things to happen automagically. Additionally, attributes are usually considered only as metadata in the IL, and as such: the parameters for them must be expressed as constants, not as runtime values. Obviously this changes if you only ever create the attributes as objects, not as metadata, but: your example shows metadata.
To do what you want, you could do it manually, i.e. have some method on ByteSerializeAttribute, and when your code detects (via PropertyInfo) that the attribute is there, use something like:
var value = property.GetValue(obj);
attrib.SomeMethod(obj, value); // or whatever you need

Related

Get property default value as expression using reflection

In order to build a custom transpiler, I'm trying to get the default value of all the properties inside a class as an expression, and not as a value itself.
Let me bring you some examples to clarify what I'm trying to do and what I've done/tried/investigated so far.
Source code could be the following one:
const string DATETIME_NOW = "____DATETIME_NOW____";
public class Person {
[DefaultValue("Foo")]
public string Name { get; set; } = "Foo";
[DefaultValue(DateTime.Now)] // This is not doable: "An attribute argument must be a constant expression"
public DateTime DateOfBirth { get; set; } = DateTime.Now;
[DefaultValue(DATETIME_NOW)]
public string DateOfBirthStringed { get; set; } = DATETIME_NOW; // which acts like DateTime.Now.ToString()
}
The ultimate goal of the transpiler, is to obtain a Javascript class that looks like this:
class Person {
name: string = "Foo";
dateOfBirth: Date = new Date(Date.now());
dateOfBirthStringed : Date = Date.now();
}
My current, and working, implementation is the use of DefaultValue attribute with some constants strings used when the default value is an expression (e.g. DateOfBirthStringed).
What I'm doing is using reflection on Person, getting all the PropertyInfo, looking for their DefaultValue attribute, and then checking if the given default value are some fixed constants like DATETIME_NOW.
This works, but I've a couple of problems:
The type in attribute DefaultValue could be different from the type of the property.. No type check :(
If I only have the DefaultValue, when I write new Person(), the default values are not actually set from the attribute.
Therefore, I need to write the default value after { get; set; }, but:
Or I wrote both attribute and default value, but then I should manually mantain synchronized them.
I write only the default value, but then I've no way to get it with reflection.
About point 3.2, why I can't get the default value via reflection?
Suppose the Person class defined above; if I use reflection, I need to instantiate it, but once instantiated, Person.DateOfBirth has an actual DateTime value, and I cannot know it was coming from DateTime.Now.
Also, if Person would be abstract.. Well, no way to instantiate it.
So, basically, the only way I could perfectly transpile the code is to read the code as a tree, something like parseTreeCode(typeof(Person)). At that point, I should navigate the tree and be able to do everything I want.
I did find Roslyn, which allows me to parse C# code, but.. It parses "stringed" code, and not code that belongs to the same project. I thought "well, get the file where Person is defined, and parse the whole file", but unfortunately, once the program is running, I cannot get the file where Person is defined.. I mean, I can do typeof(Person).Assembly, and getting the Assembly.. But it would be an assembly, so it would not be good.
At this point, I'm thinking that there is no real solution for this, but maybe I'm missing some C# packages/features that could help me

Should I use a field or a property?

First of all, I have read the question asking for the difference between fields and properties and I know what it is used for.
Now on to my question, I wanted to create a property where I am sure that get and set will both be empty, so I do get; set;. All good and well. But now I realised that I have just made a public field with a capital name, it is in all ways identical.
Even the argument of it being used so future code does not depend on implementation cannot be said, as I can simply make this a property and implement a getter or a setter. The semantics of a field and a property are identical outside the class it is defined in.
So my question is, should I use a field or a property when a property would simply use get;set;?
So this:
public IEnumerable<string> Products;
is identical in all ways to this:
public IEnumerable<string> Products { get; set; }
should I use a field or a property when a property would simply use get;set;?
Use a property... for the practical reasons below, and for the philosophical reasons that properties expose a state API, whereas fields expose a state implementation detail.
The semantics of a field and a property are identical outside the class it is defined in.
That's not true.
The difference is visible via reflection, which is often very important. For example, many binding frameworks won't use fields, only properties.
You can pass a mutable field by ref, but not a property - so changing a field to a property breaks source compatibility. (Code using SomeMethod(ref x.Products) will become invalid when Products becomes a property.)
Changing a field to a property also breaks binary compatibility, so if assembly X was built against assembly Y v1.0, and you change a field to a property for assembly Y v1.1, then you'd need to rebuild assembly X or it would fail to execute correctly
If you have a mutable value type (please don't do this) then writing foo.Location.X = 10 works when Location is a field (because x.Location is classified as a variable) whereas it doesn't when Location is a property (because then the expression x.Location is classified as a value). If you have a method (in your evil mutable type) which mutates the value instead, then foo.Location.DoSomething() will compile in both cases, but have a different effect. Fun for all the family.
Its depend on the situation. I'll prefer to use the property over the field. You have mentioned that public IEnumerable<string> Products; and public IEnumerable<string> Products { get; set; } are same, but in actual they are not. During compilation the property will get converted into two methods (i.e. get_Products() and set_Products()).
The advantage of property is to allows you to specify the custom code before assigning and returning the data, this is not possible with the field. Check the example below
public IEnumerable<string> Products
{
get
{
if(DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//Return future product
return new List<string>();
}
else
{
// return current products
return new List<string>() { "testing" };
}
}
set
{
if (DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//ignore assign product
Products = new List<string>();
}
else
{
// add assign product
Products = value;
}
}
}
Using the auto-property syntax is preferable because it creates a read/write property with a private backing field, thus allowing you to change the implementation (from a private scalar field to a dictionary entry or another backend with some other custom logic), thus freeing the "class's interface" (not the same thing as an interface) from its implementation.
Note that for collection member properties, it is advisable to make their setters private, like so:
public IEnumerable<String> Products { get; private set;}
...that way only the containing class can alter it.
Another alternative is the private readonly field, in C# 6 you can use auto-implemented properties with readonly backing fields like so:
public IEnumerable<String> Products { get; } = SomeSource.GetProducts();

How do I programmatically determine if a type is natively serializable by protobuf-net?

I am dynamically creating a RuntimeTypeModel by reflecting over types. When I reflect over a type, I look at each of its properties and determine the tag (using my own mechanism) and add it to the MetaType. I also need to determine whether the type of the property is a nested message in itself rather than a primitive that is natively serializable by protobuf-net, so that I can recursively process that type as well, thereby adding it to the model and making the outer type serializable by protobuf-net.
For example, let's say I am reflecting over the following type:
public class Foo
{
public int Number { get; set; }
public string Text { get; set; }
public Bar InnerMessage { get; set; }
}
public class Bar
{
TimeSpan Duration { get; set; }
}
I've been asked to serialize Foo and for each type of each of its properties I need to determine whether I need to add it to the model as a new MetaType or not. Obviously, the int,string and TimeSpan types do not need to be added to the model, but Bar does. How would I make this distinction programmatically? Do I need to hardcode this logic (with a switch block or an if-else chain)? If so, what types does protobuf-net r480 natively support (i.e. adding them to the model will throw an ArgumentException stating that "Data of this type has inbuilt behaviour, and cannot be added to a model in this way")?
r583 adds support for this, by extending the current CanSerializeContractType; there is now a CanSerializeBasicType, and an over-arching CanSerialize. As before, this retains the existing support for handling nullable types, lists (non-nested) and 1-dimensional arrays.

Recommended Implementation For Fields From Another System With Non-.Net Data Types

I am reading data from another system that returns XML that provides the following information for each field:
"Field Name", "Data Type", and "Size". The "Data Type" returned is either: Alpha, LAlpha, RAlpha, CAlpha, or Numeric. Sometimes there are other attributes returned as well, such as Casing. I would like to create objects to model the data returned and also have to generate xml with element values formatted according to the given data type to send back to the other system to perform transactions. I started off creating an object that would represent each property on the object like:
//Type T represents the data type of the Value property
public class OtherSystemField<T> : IOtherSystemField{
public string OtherSystemFieldName { get; set;}
public OtherSystemDataTypeEnum OtherSystemDataType { get; set;}
public int Size { get; set;}
public T Value { get; set;}
public string ToOtherSystemString() { ....};
}
//Class using the data field
public OtherSystemEntityClass {
public OtherSystemField<string> f1 { get; set; }
public OtherSystemEntityClass () {
f1 = new OtherSystemField<string>() {
OtherSystemFieldName = "x", Size = 4, OtherSystemDataType = ...};
f1.Value = "DefaultStringValue";
}
}
The question is does this representation of the other system's data fields make the most sense, using this type of object to model a field from the other system instead of a .Net data type property that is associated with some meta-data?. Any opinions on, say, having the property have attributes containing these values like:
public OtherSystemEntityClass {
[OtherSystemFieldName("SomeFieldName", 5, OtherSystemDataTypeEnum.RAlpha)]
public string f1 { get; set; }
}
Here is an example of the XML:
<COLUMNS>
<COLUMN header="FieldX" dspname="FieldX" dbname="FIELDX" type="NUMERIC" size="4" />
<COLUMN header="FieldY" dspname="FieldY" dbname="FIELDY" type="ALPHARIGHT" size="14"/>
</COLUMNS> <COLS> <COL><![CDATA[ 1000]]></COL> <COL><![CDATA[ 102]]></COL> </COLS>
I look forward to everyone's feedback - I have no doubts I will hear good perspectives.
Performance is not of a huge concern, as the number of fields is relatively small. Also, this is implemented in .Net 3.5
I'm not sure what the "Alpha" types are, but the newly-added XML snippet is clearly describing a table schema. If you can pull off a mapping, I might actually use a DataTable instead of creating any custom classes at all.
I wouldn't be too surprised to find out that the XML is literally serialized directly from something similar to a .NET DataSet/DataTable but in a different language/platform. Those CDATA tags are not consumer-friendly. But if you can map Alpha values to some enum type (most likely a custom one you create), then you can just add a column of that type to a DataTable.
Do you already know the Field Name, Data Type, Size, etc of your fields or is this something that you need to determine at run time? If you already know all the information about the fields at design time, then I like the attribute approach. I've done the very same when dealing with incoming Xml from old systems. You can then deserialize the Xml to your objects, and you're good to go.
If you do not know the format of the Xml at design time, that is, you need to set the attribute values at run time, then using attributes will be more difficult than your first approach. You would need to set the attributes with reflection, which would be more work than just setting a property in the first solution.

How to make a Attribute aware of the Name of the Proprty it is on?

I want to implement a simple attribute that is used to map Database Columns to Properties.
So what i have so far is something that attached like so:
[DataField("ID")]
public int ID { get; set; }
[DataField("Name")]
public String Name { get; set; }
[DataField("BirD8")]
public DateTime BirthDay { get; set; }
Is there a way that I can make the attribute "aware" of the field it is on, so that for the properties where the name is the same as the ColumnName I can just apply the attribute without the name parameter, or would I have to deal with that at the point where I reflect the properties. I want to end up doing just this:
[DataField]
public int ID { get; set; }
[DataField]
public String Name { get; set; }
[DataField("BirD8")]
public DateTime BirthDay { get; set; }
The attribute itself won't be aware of what it's applied to, but the code processing the attributes is likely to be running through PropertyInfo values etc and finding the attributes associated with them. That code can then use both the property and the attribute appropriately.
To make things simpler, you might want to write a method on the attribute to allow it to merge its information with the information from the property, so you'd call:
DataFieldAttribute dfa = propertyInfo.GetCustomAttributes(...); // As normal
dfa = dfa.MergeWith(propertyInfo);
Note that for the sake of sanity this should create a new instance of the attribute, rather than changing the existing one. Alternatively, you might want a whole separate class to represent "the information about a data field":
DataFieldAttribute dfa = propertyInfo.GetCustomAttributes(...); // As normal
DataFieldInfo info = dfa.MergeWith(propertyInfo);
That way you could also construct DataFieldInfo objects without any reference to attributes, which might be a nice conceptual separation - allowing you to easily load the config from an XML file or something similar if you wanted to.
If you don't mind using postsharp you can look Here, at a previous question I have asked which was close. I ended up using the compile time validate to do what I wanted, although there are other options, like CompileTimeInitalize.
public override void CompileTimeInitialize(object element)
{
PropertyInfo info = element as PropertyInfo;
//....
}

Categories