For a project i've created several struct in C#.
The probject itself is a ASP.Net MVC 2 project.
snip:
struct TDummy
{
private char _value;
public TDummy(char value)
{
this._value = value; // Restrictions
}
}
I created this because I needed to restrict a char-variable to a specific number of values. (I could have created an Enum, but these values are also used in the database, and then i would still need to convert them)
Now i need to create a JsonResult, like
return Json(new { Value = new TDummy('X') });
But when I do this, I get a result of:
{"Value":{}}
I expected to get a result of
{"Value":"X"}
I've tried several things, like TypeConverter (CanConvertTo(string)), Custom Type Serializer (JavaScriptSerializer.RegisterConverters()), but either they don't work or they must return a 'Complex' json-object.
{"Value":{"Name":"Value"}}
Any thoughts on this?
I want to serialize a value-type as a value...
If anyone is interested, i've create a small demo (console app) to illustrate this:
public struct TState
{
public static TState Active = new TState('A');
public static TState Pending = new TState('P');
private char _value;
public TState(char value)
{
switch (value)
{
case 'A':
case 'P':
this._value = value; // Known values
break;
default:
this._value = 'A'; // Default value
break;
}
}
public static implicit operator TState(char value)
{
switch (value)
{
case 'A':
return TState.Active;
case 'P':
return TState.Pending;
}
throw new InvalidCastException();
}
public static implicit operator char(TState value)
{
return value._value;
}
public override string ToString()
{
return this._value.ToString();
}
}
public class Test { public TState Value { get; set; } }
class Program
{
static void Main(string[] args)
{
Test o = new Test();
o.Value = 'P'; // From Char
char c = o.Value; // To Char
Console.WriteLine(o.Value); // Writes 'P'
Console.WriteLine(c); // Writes 'P'
JavaScriptSerializer jser = new JavaScriptSerializer();
Console.WriteLine(jser.Serialize(o)); // Writes '{"Value":{}}'
Console.ReadLine();
}
}
Related
I have started to use C# 7's type based pattern matching. A method that only manages a single pattern-based result looks very clean and is easy to reason about.
However, once a second pattern-based result that depends on the first pattern-based result creates an arrow anti-pattern, and will only get worse with n-results that depend on each other.
Here is an simplified example that demonstrates the arrow pattern:
public Result<bool> ValidateSomething(string strId)
{
var id = Guid.Parse(strId);
Result<Something> fetchSomethingResult = new SomethingDao.FetchSomething(id);
switch (fetchSomethingResult)
{
case ValueResult<Something> successfulSomethingResult:
Result<Related> fetchRelatedFieldsResult = new RelatedDao.FetchRelatedFields(successfulSomethingResult.Value.RelatedId);
switch (fetchRelatedFieldsResult)
{
case ValueResult<Related> successfulFieldValueResult:
var isValid = successfulSomethingResult.Value.ComparableVal <= successfulFieldValueResult.Value.RelatedComparableVal;
return new ValueResult<bool>(isValid);
case ValueNotFoundResult<Related> _:
return new ValueNotFoundResult<bool>();
case ErrorResult<Related> errorResult:
return new ErrorResult<bool>(errorResult.ResultException);
default:
throw new NotImplementedException("Unexpected Result Type Received.");
}
case ValueNotFoundResult<Something> notFoundResult:
return new ValueNotFoundResult<bool>();
case ErrorResult<Something> errorResult:
return new ErrorResult<bool>(errorResult.ResultException);
default:
throw new NotImplementedException("Unexpected Result Type Received.");
}
}
For reference, these are the definitions for the Result classes:
public abstract class Result<T>
{
}
public class ValueResult<T> : Result<T>
{
public ValueResult()
{
}
public ValueResult(T inValue)
{
Value = inValue;
}
public T Value { get; set; }
}
public class ValueNotFoundResult<T> : Result<T>
{
public ValueNotFoundResult()
{
}
}
public class ErrorResult<T> : Result<T>
{
public Exception ResultException { get; set; }
public ErrorResult()
{
}
public ErrorResult(Exception resultException)
{
ResultException = resultException;
}
}
What options are there to handle this type of code better? What suggestions do you have for the previous examples? How do I avoid the arrow anti-pattern with pattern-based results?
Since you are only really doing anything with the result in case it was successfull, it seem fairly simple to move the switch to an extension method. You might need two extensions, depending on if the function return a new result or just T, something like :
public static Result<TOut> SelectValue<TIn, TOut>(this Result<TIn> self, Func<TIn, Result<TOut>> select)
{
switch (self)
{
case ErrorResult<TIn> errorResult: return new ErrorResult<TOut>(errorResult.ResultException);
case ValueNotFoundResult<TIn> valueNotFoundResult: return new ValueNotFoundResult<TOut>();
case ValueResult<TIn> valueResult: return select(valueResult.Value);
default: throw new ArgumentOutOfRangeException(nameof(self));
}
}
public static Result<TOut> SelectValue<TIn, TOut>(this Result<TIn> self, Func<TIn, TOut> select)
{
switch (self)
{
case ErrorResult<TIn> errorResult: return new ErrorResult<TOut>(errorResult.ResultException);
case ValueNotFoundResult<TIn> valueNotFoundResult: return new ValueNotFoundResult<TOut>();
case ValueResult<TIn> valueResult: return new ValueResult<TOut>(select(valueResult.Value));
default: throw new ArgumentOutOfRangeException(nameof(self));
}
}
You can then handle the success-cases like this:
var result = fetchSomethingResult
.SelectValue(something => new RelatedDao.FetchRelatedFields(something.RelatedId))
.SelectValue(related => related.CompareVal >= 5);
If you need to use values from both "Something" and "Related" you will unfortunately need to nest calls.
var result = fetchSomethingResult
.SelectValue(something => new RelatedDao.FetchRelatedFields(something.RelatedId).SelectValue(related => related.CompareVal >= 5));
Background
In .NET Core, default controller model binding fails (produces null value for your action argument) if your model contains an enum anywhere in its hierarchy and the supplied values don't match EXACTLY with the names in the enum. White-space or odd capitalization breaks the binding, and that seems unfriendly for the consumer of my API endpoint.
My solution
I created a model binder provider, which uses reflection to determine if somewhere in the target binding type there exists an enum; if this check is true, it returns a custom model binder (constructed by passing along the enum type) which uses Regex/string manipulation (gross) to scan the request body for the enum values and make an effort to resolve them to a name in that enum type, before passing JsonConvert for deserializing.
This solution is, in my opinion, far too complex and ugly for what I'm trying to achieve.
What I'd like is something like a JsonConvert attribute (for my enum fields) that makes this effort during binding/deserialization. Newtonsoft's out of the box solution (StringEnumConverter) doesn't try to adjust the string to fit the enum type (fair, I suppose), but I can't extend Newtonsoft's functionality here because it relies on a lot of internal classes (without copying and pasting a ton's of their code).
Is there a piece in the pipeline somewhere I'm missing that could be better leveraged to fit this need?
P.S. I placed this here rather than code review (it's too theoretical) or software engineering (too specific); please advise if it's not the right place.
I've used a Type Safe Enum pattern for this, I think it will work for you. With the TypeSafeEnum you can control what is mapped to the JSON using Newtonsoft's JsonConverter attribute. Since you have no code to post I've built up a sample.
Base class used by your application's TypeSafeEnums:
public abstract class TypeSafeEnumBase
{
protected readonly string Name;
protected readonly int Value;
protected TypeSafeEnumBase(int value, string name)
{
this.Name = name;
this.Value = value;
}
public override string ToString()
{
return Name;
}
}
Sample type implemented as a TypeSafeEnum, it would have normally been a plain Enum, including Parse and TryParse methods:
public sealed class BirdType : TypeSafeEnumBase
{
private const int BlueBirdId = 1;
private const int RedBirdId = 2;
private const int GreenBirdId = 3;
public static readonly BirdType BlueBird =
new BirdType(BlueBirdId, nameof(BlueBird), "Blue Bird");
public static readonly BirdType RedBird =
new BirdType(RedBirdId, nameof(RedBird), "Red Bird");
public static readonly BirdType GreenBird =
new BirdType(GreenBirdId, nameof(GreenBird), "Green Bird");
private BirdType(int value, string name, string displayName) :
base(value, name)
{
DisplayName = displayName;
}
public string DisplayName { get; }
public static BirdType Parse(int value)
{
switch (value)
{
case BlueBirdId:
return BlueBird;
case RedBirdId:
return RedBird;
case GreenBirdId:
return GreenBird;
default:
throw new ArgumentOutOfRangeException(nameof(value), $"Unable to parse for value, '{value}'. Not found.");
}
}
public static BirdType Parse(string value)
{
switch (value)
{
case "Blue Bird":
case nameof(BlueBird):
return BlueBird;
case "Red Bird":
case nameof(RedBird):
return RedBird;
case "Green Bird":
case nameof(GreenBird):
return GreenBird;
default:
throw new ArgumentOutOfRangeException(nameof(value), $"Unable to parse for value, '{value}'. Not found.");
}
}
public static bool TryParse(int value, out BirdType type)
{
try
{
type = Parse(value);
return true;
}
catch
{
type = null;
return false;
}
}
public static bool TryParse(string value, out BirdType type)
{
try
{
type = Parse(value);
return true;
}
catch
{
type = null;
return false;
}
}
}
Container to handle type safe conversion, so you don't need to create a converter for every type safe implemented, and to prevent changes in the TypeSafeEnumJsonConverter when new type safe enums are implemented:
public class TypeSafeEnumConverter
{
public static object ConvertToTypeSafeEnum(string typeName, string value)
{
switch (typeName)
{
case "BirdType":
return BirdType.Parse(value);
//case "SomeOtherType": // other type safe enums
// return // some other type safe parse call
default:
return null;
}
}
}
Implements Newtonsoft's JsonConverter which in turn calls our TypeSafeEnumConverter
public class TypeSafeEnumJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
var types = new[] { typeof(TypeSafeEnumBase) };
return types.Any(t => t == objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string name = objectType.Name;
string value = serializer.Deserialize(reader).ToString();
return TypeSafeEnumConversion.ConvertToTypeSafeEnum(name, value); // call to our type safe converter
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null && serializer.NullValueHandling == NullValueHandling.Ignore)
{
return;
}
writer.WriteValue(value?.ToString());
}
}
Sample object that uses our BirdType and sets the converter to use:
public class BirdCoup
{
[JsonProperty("bird-a")]
[JsonConverter(typeof(TypeSafeEnumJsonConverter))] // sets the converter used for this type
public BirdType BirdA { get; set; }
[JsonProperty("bird-b")]
[JsonConverter(typeof(TypeSafeEnumJsonConverter))] // sets the converter for this type
public BirdType BirdB { get; set; }
}
Usage example:
// sample #1, converts value with spaces to BirdTyp
string sampleJson_1 = "{\"bird-a\":\"Red Bird\",\"bird-b\":\"Blue Bird\"}";
BirdCoup resultSample_1 =
JsonConvert.DeserializeObject<BirdCoup>(sampleJson_1, new JsonConverter[]{new TypeSafeEnumJsonConverter()});
// sample #2, converts value with no spaces in name to BirdType
string sampleJson_2 = "{\"bird-a\":\"RedBird\",\"bird-b\":\"BlueBird\"}";
BirdCoup resultSample_2 =
JsonConvert.DeserializeObject<BirdCoup>(sampleJson_2, new JsonConverter[] { new TypeSafeEnumJsonConverter() });
I use a framework which exposes an abstract class called Value. Through operator overloading, it's possible to assign almost anything to this class's objects, and it works like a charm:
Value a = "hello";
Value b = 1;
Value c = true;
Value d = 3.14;
(Note that this is the only way to create instances of Value. There are no public/protected ways to assign values to instances, other than the overloaded operators.)
Right now, I want to override the implicit operator Value(string input) function, so that it XML-sanitizes any string before assigning it.
I have tried inheriting this class and overriding the operator, but have not found a way to feed the sanitized string into the base class's operator function. The following obviously doesn't work:
public override static implicit operator XmlValue(string input)
{
string output = sanitize(input);
XmlValue rv = null;
((Value)rv) = output; // this is not possible
return rv;
}
Is there a way to achieve this? Or alternatively, am I perhaps overthinking the problem and is there a better solution for what I want to do? In any case, I'd like to avoid having to sanitize each and every string before assigning it to a Value; this would be way too error prone.
FYI: the Value class is part of the Cottle framework.
The important point is that you cannot "override" operators, because they are static. You can instead define a new operator in your derived class, then make the assignment using a variable of your derived type (so that the compiler knows that it needs to call the operator of the derived class).
Look at this example:
using System;
class Value {
public string StringValue {
get;
private set;
}
protected Value(string str) {
StringValue = str;
}
public static implicit operator Value(string input) {
return new Value(input);
}
}
class XmlValue : Value {
protected XmlValue(string str) : base(str) {
}
public static implicit operator XmlValue(string input) {
// using "ToUpperInvariant" instead of sanitize
return new XmlValue(input.ToUpperInvariant());
}
}
class Program {
static void Main(string[] args) {
Value v1 = "test";
Console.WriteLine(v1.StringValue); // "test"
XmlValue v2 = "test";
Console.WriteLine(v2.StringValue); // "TEST"
}
}
After checking your comment, I think that the example below is more related to the real situation you are facing.
However, as fun as this operators overloading might be, I think that in this case you should definitely opt for the simpler and more readable solution of sanitizing every input before assignment.
using System;
abstract class Value {
public string StringValue {
get;
protected set;
}
public static implicit operator Value(string input) {
return new StringValue(input);
}
}
class StringValue : Value {
public StringValue(string str) {
StringValue = str;
}
}
class Xml {
string _value;
public Xml(string value) {
_value = value;
}
public static implicit operator Xml(string input) {
return new Xml(input.ToUpperInvariant());
}
public static implicit operator Value(Xml xml) {
Value ret = xml._value;
return ret;
}
}
class Program {
static void Main(string[] args) {
// this works with the cast operators...
Value v1 = (Xml)"test";
Console.WriteLine(v1.StringValue); // "TEST"
// ...but I would definitely go for this:
Value v2 = sanitize("test");
}
}
How can I use reflection to get the name and declaring class of a property of a generic type. The purpose is to get an exception if I read a property where nothing has been written so far. One of the problems is that the check must be independent of the declaring class.
value.GetType().DeclaringType is always null.
using System;
namespace TestCodeContract
{
public struct CheckForNull<T> where T : struct
{
private T? backingField;
public static implicit operator T(CheckForNull<T> value)
{
if (!(value.backingField.HasValue))
{
var t1 = value.GetType().DeclaringType; // always null.
var propertyName = "Delta"; // TODO get from Reflection
var className = "ContractClass"; // TODO get from Reflection
var msg = String.Format("Proprety '{0}' in class '{1}' is not initialized", propertyName, className);
throw new ApplicationException(msg);
}
return value.backingField.Value;
}
public static implicit operator CheckForNull<T>(T value)
{
return new CheckForNull<T> { backingField = value };
}
}
public class ContractClass
{
public CheckForNull<int> Delta { get; set; }
public void Test1()
{
int x = Delta; // Wanted: "Property 'Delta' in class 'ContractClass' is not initialized"
}
}
}
No, you can't do it like that. I would suggest something like this instead:
// You could do this without the constraint, with a bit of extra work.
public class ReadOnlyAfterWrite<T> where T : struct
{
private T? value;
private readonly string property;
private readonly string type;
public ReadOnlyAfterWrite(string property, string type)
{
this.property = property;
this.type = type;
}
public T Value
{
get
{
if (value == null)
{
// Use type and property here
throw new InvalidOperationException(...);
}
return (T) value;
}
set { this.value = value; }
}
}
public class ContractClass
{
// This is what I'd do in C# 6. Before that, probably just use string literals.
private readonly ReadOnlyAfterWrite<int> delta =
new ReadOnlyAfterWrite(nameof(Delta), nameof(ContractClass));
public int Delta
{
get { return delta.Value; }
set { delta.Value = value; }
}
}
While it's not terribly clean in implementation, I think it's a better public API - the fact that it's guarded is invisible to the caller, who just sees an int property.
I am trying to combine a bunch of similar methods into a generic method. I have several methods that return the value of a querystring, or null if that querystring does not exist or is not in the correct format. This would be easy enough if all the types were natively nullable, but I have to use the nullable generic type for integers and dates.
Here's what I have now. However, it will pass back a 0 if a numeric value is invalid, and that unfortunately is a valid value in my scenarios. Can somebody help me out? Thanks!
public static T GetQueryString<T>(string key) where T : IConvertible
{
T result = default(T);
if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
{
string value = HttpContext.Current.Request.QueryString[key];
try
{
result = (T)Convert.ChangeType(value, typeof(T));
}
catch
{
//Could not convert. Pass back default value...
result = default(T);
}
}
return result;
}
What if you specified the default value to return, instead of using default(T)?
public static T GetQueryString<T>(string key, T defaultValue) {...}
It makes calling it easier too:
var intValue = GetQueryString("intParm", Int32.MinValue);
var strValue = GetQueryString("strParm", "");
var dtmValue = GetQueryString("dtmPatm", DateTime.Now); // eg use today's date if not specified
The downside being you need magic values to denote invalid/missing querystring values.
I know, I know, but...
public static bool TryGetQueryString<T>(string key, out T queryString)
What about this? Change the return type from T to Nullable<T>
public static Nullable<T> GetQueryString<T>(string key) where T : struct, IConvertible
{
T result = default(T);
if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
{
string value = HttpContext.Current.Request.QueryString[key];
try
{
result = (T)Convert.ChangeType(value, typeof(T));
}
catch
{
//Could not convert. Pass back default value...
result = default(T);
}
}
return result;
}
Convert.ChangeType() doesn't correctly handle nullable types or enumerations in .NET 2.0 BCL (I think it's fixed for BCL 4.0 though). Rather than make the outer implementation more complex, make the converter do more work for you. Here's an implementation I use:
public static class Converter
{
public static T ConvertTo<T>(object value)
{
return ConvertTo(value, default(T));
}
public static T ConvertTo<T>(object value, T defaultValue)
{
if (value == DBNull.Value)
{
return defaultValue;
}
return (T) ChangeType(value, typeof(T));
}
public static object ChangeType(object value, Type conversionType)
{
if (conversionType == null)
{
throw new ArgumentNullException("conversionType");
}
// if it's not a nullable type, just pass through the parameters to Convert.ChangeType
if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
// null input returns null output regardless of base type
if (value == null)
{
return null;
}
// it's a nullable type, and not null, which means it can be converted to its underlying type,
// so overwrite the passed-in conversion type with this underlying type
conversionType = Nullable.GetUnderlyingType(conversionType);
}
else if (conversionType.IsEnum)
{
// strings require Parse method
if (value is string)
{
return Enum.Parse(conversionType, (string) value);
}
// primitive types can be instantiated using ToObject
else if (value is int || value is uint || value is short || value is ushort ||
value is byte || value is sbyte || value is long || value is ulong)
{
return Enum.ToObject(conversionType, value);
}
else
{
throw new ArgumentException(String.Format("Value cannot be converted to {0} - current type is " +
"not supported for enum conversions.", conversionType.FullName));
}
}
return Convert.ChangeType(value, conversionType);
}
}
Then your implementation of GetQueryString<T> can be:
public static T GetQueryString<T>(string key)
{
T result = default(T);
string value = HttpContext.Current.Request.QueryString[key];
if (!String.IsNullOrEmpty(value))
{
try
{
result = Converter.ConvertTo<T>(value);
}
catch
{
//Could not convert. Pass back default value...
result = default(T);
}
}
return result;
}
You can use sort of Maybe monad (though I'd prefer Jay's answer)
public class Maybe<T>
{
private readonly T _value;
public Maybe(T value)
{
_value = value;
IsNothing = false;
}
public Maybe()
{
IsNothing = true;
}
public bool IsNothing { get; private set; }
public T Value
{
get
{
if (IsNothing)
{
throw new InvalidOperationException("Value doesn't exist");
}
return _value;
}
}
public override bool Equals(object other)
{
if (IsNothing)
{
return (other == null);
}
if (other == null)
{
return false;
}
return _value.Equals(other);
}
public override int GetHashCode()
{
if (IsNothing)
{
return 0;
}
return _value.GetHashCode();
}
public override string ToString()
{
if (IsNothing)
{
return "";
}
return _value.ToString();
}
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>(value);
}
public static explicit operator T(Maybe<T> value)
{
return value.Value;
}
}
Your method would look like:
public static Maybe<T> GetQueryString<T>(string key) where T : IConvertible
{
if (String.IsNullOrEmpty(HttpContext.Current.Request.QueryString[key]) == false)
{
string value = HttpContext.Current.Request.QueryString[key];
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch
{
//Could not convert. Pass back default value...
return new Maybe<T>();
}
}
return new Maybe<T>();
}
I like to start with a class like this
class settings
{
public int X {get;set;}
public string Y { get; set; }
// repeat as necessary
public settings()
{
this.X = defaultForX;
this.Y = defaultForY;
// repeat ...
}
public void Parse(Uri uri)
{
// parse values from query string.
// if you need to distinguish from default vs. specified, add an appropriate property
}
This has worked well on 100's of projects. You can use one of the many other parsing solutions to parse values.