Is it possible to create an object with a property name that contains a dash character?
I am creating an anonymous object so that I can serialize it to Json using Json.Net and one of the properties I need contains a '-' dash character.
An example of what I want is:
var document = {
condtions = new {
acl = "public-read",
bucket = "s3-bucketname",
starts-with = "test/path"
}
};
I know I could replace the dash with underscores when creating the object and then replace them in the serialized string afterwards, but wanted to know if there is a way in the language to do this without this workaround.
You can't do this with anonymous objects; field names must be valid identifiers. You could instead use a Dictionary, which Json.Net should serialise just as easily as an anonymous object:
var document = new {
conditions = new Dictionary<string, string>() {
{ "acl", "public-read" },
{ "bucket", "s3-bucketname" },
{ "starts-with", "test/path" }
}
};
Not in c#, no. However most serializers allow you to customise this - often via attributes. IIRC with JSON.NET you want [JsonProperty("starts-with")] to specify the name. However you can't use attributes on anonymous types, so you may need to define a class with the properties (and attributes) the you desire.
Unfortunately, that's not possible, because the language would not be able to differentiate the two following expressions:
condition.starts-with; // Read "starts-with" property.
condition.starts - with; // Read "starts" property and subtract "with" variable.
Related
How can I DeserializeObject the following JSON string to a C# object
{"":["Waybill already exist"]}
In some instances the "" can contain a value as well
Like
{"RecevierAddress1" : ["Receiver address 1 can not be blank]}
Whereas what You ask is not possible in principle, because an object property must have a name, what you can do is convert it to a .net JsonDocument which can have properties of zero length string naming.
I presume RL data cause for you to have to handle this, which of cause indicates poor data quality besides that, but You should be able to process it using this technique, here from a unit test
[Fact]
public void SerializeSillyObjectJsonTest()
{
string serialized = "{\"\":[\"Waybill already exist\"]}";
var jdoc = System.Text.Json.JsonDocument.Parse(serialized);
Assert.NotNull(jdoc);
var jsonElement = jdoc.RootElement.GetProperty("");
Assert.Equal(1, jsonElement.GetArrayLength());
}
So You see you can also check on if your property with said name exist and choose what to look for
jdoc.RootElement.TryGetProperty("RecevierAddress1", out var receiverAddressElement)
You can use JsonProperty("") to set the property name to an empty string
class root
{
[JsonProperty("")]
public string[] x;
}
JsonConvert.DeserializeObject<root>(#"{"""":[""Waybill already exist""]}")
For dynamic names, you can either have two properties, or deserialize to a dictionary
JsonConvert.DeserializeObject<Dictionary<string, string[]>>(#"{"""":[""Waybill already exist""]}")
I am trying to build a solution fitting with the problem of not knowing what kind of Setting type I am dealing with.
I got a Dictionary<string, Type> (which I initially wanted to make <string, class> but that didn't work)
that I want to fill with the setting code and the type of class attached to it i.e.
{ "person_customField", typeof(CustomFieldModel) }
Why I want to do this is because I have a field in my database filled with json data that should be deserialized to a List<> but I don't know what kind of setting it is until I get the object from the database. I can use the Code field to detemine what type it is (person_CustomField should use the CustomFieldModel class, but emailSetting should use EmailSettingModel to match parameters to.
Is there a way to successfully make this statement work with?
JsonConvert.DeserializeObject<List<SettingTypes[record.SettingCode]>>(record.SettingValues).ToList<ISetting>()
Or should I go a different route
Code Sample:
public static readonly Dictionary<string, Type> SettingTypes = new Dictionary<string, Type>()
{
{ "person_CustomFields", typeof(CustomFieldModel)},
};
public static TenantSettingEdit ConvertToTenantSettingEdit(this T_TenantSetting rec)
{
var test = SettingTypes[rec.TENS_Code];
TenantSettingEdit item = new TenantSettingEdit()
{
IDToken = rec.TENS_TenantSettingID.toVirtualGuid().ToString(),
Code = rec.TENS_Code,
Settings = JsonConvert.DeserializeObject<List<SettingTypes[rec.TENS_Code]>>(rec.TENS_Setting).ToList<ITenantSetting>(),
IsActive = rec.TENS_ActiveRec,
};
return item;
}
(I have done this before with PHP but I am not sure if this is even remotely possible with C#)
Why I want to do this is because I have a field in my database filled
with json data that should be deserialized to a List<> but I don't
know what kind of setting it is until I get the object from the
database.
If you're using Json.Net for JSON serialization/deserialization you can use the TypeNameHandling property to embed Type information in the resulting JSON. That JSON can the be deserialized by Json.Net without additional information. If it is necessary to map custom values to the types instead of the automatically generated ones you can use a SerializationBinder (check out this answer).
If none of those help you, you can still fall back to reflection in the way M Kloster describes.
You cannot use a variable as the type parameter in the code, no. What you need to do is to generate the type-specific method by reflection:
var genericMethod = ((Func<string, int>)Json.DeserializeObject<int>).Method.GetGenericMethodDefinition();
var boundMethod = genericMethod.MakeGenericMethod(SettingTypes[record.SettingCode]);
var result = boundMethod.Invoke(null, rec.TENS_Setting)...
I want to add attributes to properties of a class. I want to store attributes into an XML and read from there. I don't want to add them manually like this,
[CategoryIndex("1", "StackPanel")]
[FrameAttribute("abc")]
[PositionAttribute("0","1","0")]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
I want to store all the attributes in an XML file and read from there.. How to proceed ?
This sounds like a job for the amazing ExpandoObject.
Excerpt:
You create an ExpandoObject instance as you do with any other .NET object, except that the variable to store the instance is of type dynamic:
dynamic expando = new ExpandoObject();
At this point, to add a property to the expando you simply assign it a new value, as below:
expando.FirstName = "Dino";
The link also includes saving and retrieving the properties to XML files.
I need to create the ability to drill through an objects properties like two or three deep. For instance, class A has a property reference to class B, which I need to access class C. What is the best way to do this: straight reflection, or maybe using the TypeDescriptor, or something else?
Thanks.
It's not too hard to write. I put a few classes together to deal with this so I could serialize properties of a WinForm. Take a look at this class and the related classes.
http://csharptest.net/browse/src/Library/Reflection/PropertySerializer.cs
If you know the path in a static context (ie the path is always the same) and the properties are accessible (internal or public) you can use dynamic
[Test]
public void Foo()
{
var a = new A
{
B = new B
{
C = new C
{
Name = "hello"
}
}
};
DoReflection(a);
}
private void DoReflection(dynamic value)
{
string message = value.B.C.Name;
Debug.WriteLine(message);
}
I you wanna write you own serialization code for whatever reason, you'll be using reflection.
What you do is that you write a recursive method of serlizating a type. You then apply this as you see fit to get the result.
var type = myObjectOfSomeType.GetType();
// now depending on what you want to store
// I'll save all public properties
var properties = type.GetProperties(); // get all public properties
foreach(var p in properties)
{
var value = p.GetValue(myObjectOfSomeType, null);
Writevalue(p.Name, value);
}
The implementation of WriteValue have to recognize the built in types and treat them accordingly, that's typical things like string, char, integer, double, DateTime etc.
If it encounters a sequence or collection you need to write out many values.
If it encounters a non trivial type you'll apply this recursive pattern again.
The end result is a recursive algorithm that traverses your object model and writes out values as it encounters types that I know how to serialize.
However, I do recommend looking into WCF, not for building services, but for serialization. It shipped as part of the .NET 3.0 framework with a new assembly System.Runtime.Serilization and in general is very capable when dealing with serialization and data annotations.
When I do a query that returns an anonymous type
var assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new {p.Asset, p.Asset.PropertyTbl};
Can I type the return to anything other than var?
You cannot* return an anonymous type because the caller would not know what type it is and wouldn't be able to use it.
If you want to return the results, you can create objects of a non-anonymous type:
IEnumerable<Foo> assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new Foo { Bar = p.Asset, Baz = p.Asset.PropertyTbl};
You can also use the Tuple type in .NET 4 if you don't want to create a custom class for your values.
* This is not strictly true - it is possible but you should avoid doing it. Here is a link anyway if you really want to.
You can use object or dynamic (in .NET 4.0) instead of var but don't expect to find a name to an anonymous type. In your case using var is better as it will preserve the strong typing at least until you leave the scope of the current method.
You could define a new class:
public class AssetProp
{
public virtual string Asset {get;set;}
public virtual string PropertyTbl {get;set;}
}
And then you can return it as that class:
IEnumerable<AssetProp> assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new AssetProp {p.Asset, p.Asset.PropertyTbl};
Not really, since the new {p.Asset, p.Asset.PropertyTbl} code creates an anonymous type. Even using object doesn't really gain you much since you can't cast it to anything useful later on, so you would have to use reflection to access the properties.
Not really. If you cast to object you wont be able to access the properties of your anonymous class.
The var keyword was specifically introduced for dealing with anonymous classes - why would you want to avoid it? If you need to return the data you should name the class.
You can if you use lambda expressions, otherwise you can do a cast but do some good exception handling.
you can also do this (it does relate much to your problem though, because you just move "var" somewhere else, but it's interesting that it recognize those types as same)
var element = new { id = 7 };
List<object> collection = new List<object>();
element = collection.Select(item => new { id = 0 }).First();