How to Cast to Generic Parameter in C#? - c#

I'm trying to write a generic method for fetching an XElement value in a strongly-typed fashion. Here's what I have:
public static class XElementExtensions
{
public static XElement GetElement(this XElement xElement, string elementName)
{
// Calls xElement.Element(elementName) and returns that xElement (with some validation).
}
public static TElementType GetElementValue<TElementType>(this XElement xElement, string elementName)
{
XElement element = GetElement(xElement, elementName);
try
{
return (TElementType)((object) element.Value); // First attempt.
}
catch (InvalidCastException originalException)
{
string exceptionMessage = string.Format("Cannot cast element value '{0}' to type '{1}'.", element.Value,
typeof(TElementType).Name);
throw new InvalidCastException(exceptionMessage, originalException);
}
}
}
As you can see on the First attempt line of GetElementValue, I'm trying to go from string -> object -> TElementType. Unfortunately, this does not work for an integer test case. When running the following test:
[Test]
public void GetElementValueShouldReturnValueOfIntegerElementAsInteger()
{
const int expectedValue = 5;
const string elementName = "intProp";
var xElement = new XElement("name");
var integerElement = new XElement(elementName) { Value = expectedValue.ToString() };
xElement.Add(integerElement);
int value = XElementExtensions.GetElementValue<int>(xElement, elementName);
Assert.AreEqual(expectedValue, value, "Expected integer value was not returned from element.");
}
I get the following exception when GetElementValue<int> is called:
System.InvalidCastException : Cannot cast element value '5' to type 'Int32'.
Am I going to have to handle each casting case (or at least the numeric ones) separately?

You could also try the Convert.ChangeType
Convert.ChangeType(element.Value, typeof(TElementType))

From your code, instead of:
return (TElementType)((object) element.Value);
you'd do this:
return (TElementType) Convert.ChangeType(element.Value, typeof (T));
The only caveat here is that TElementType must implement IConvertible. However, if you're just talking about intrinsic types, they all implement that already.
For your custom types, assuming you wanted them in here, you'd have to have your own conversion.

You can't do an implicit or explicit cast from String to Int32, you need use Int32's Parse or TryParse methods for this. You could probably create some nifty extension methods, e.g:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Text;
/// <summary>
/// Provides extension methods for strings.
/// </summary>
public static class StringExtensions
{
#region Methods
/// <summary>
/// Converts the specified string to a <see cref="Boolean"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="Boolean"/>.</returns>
public static bool AsBoolean(this string #string)
{
return bool.Parse(#string);
}
/// <summary>
/// Converts the specified string to a <see cref="Boolean"/> using TryParse.
/// </summary>
/// <remarks>
/// If the specified string cannot be parsed, the default value (if valid) or false is returned.
/// </remarks>
/// <param name="string">The string to convert.</param>
/// <param name="default">The default value for if the value cannot be parsed.</param>
/// <returns>The specified string as a <see cref="DateTime"/>.</returns>
public static bool AsBooleanNonStrict(this string #string, bool? #default = null)
{
bool #bool;
if ((!string.IsNullOrEmpty(#string)) && bool.TryParse(#string, out #bool))
return #bool;
if (#default.HasValue)
return #default.Value;
return false;
}
/// <summary>
/// Converts the specified string to a <see cref="DateTime"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="DateTime"/>.</returns>
public static DateTime AsDateTime(this string #string)
{
return DateTime.Parse(#string);
}
/// <summary>
/// Converts the specified string to a <see cref="DateTime"/> using TryParse.
/// </summary>
/// <remarks>
/// If the specified string cannot be parsed, <see cref="DateTime.MinValue"/> is returned.
/// </remarks>
/// <param name="string">The string to convert.</param>
/// <param name="default">The default value for if the value cannot be parsed.</param>
/// <returns>The specified string as a <see cref="DateTime"/>.</returns>
public static DateTime AsDateTimeNonStrict(this string #string, DateTime? #default = null)
{
DateTime datetime;
if ((!string.IsNullOrEmpty(#string)) && DateTime.TryParse(#string, out datetime))
return datetime;
if (#default.HasValue)
return #default.Value;
return DateTime.MinValue;
}
/// <summary>
/// Converts the specified string to a <see cref="TEnum"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="TEnum"/>.</returns>
public static TEnum AsEnum<TEnum>(this string #string) where TEnum : struct
{
return (TEnum)Enum.Parse(typeof(TEnum), #string);
}
/// <summary>
/// Converts the specified string to a <see cref="TEnum"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="TEnum"/>.</returns>
public static TEnum AsEnumNonStrict<TEnum>(this string #string, TEnum #default) where TEnum : struct
{
TEnum #enum;
if ((!string.IsNullOrEmpty(#string)) && Enum.TryParse(#string, out #enum))
return #enum;
return #default;
}
/// <summary>
/// Converts the specified string to a <see cref="Int32"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="Int32"/>.</returns>
public static int AsInteger(this string #string)
{
return int.Parse(#string);
}
/// <summary>
/// Converts the specified string to a <see cref="Int32"/> using TryParse.
/// </summary>
/// <remarks>
/// If the specified string cannot be parsed, the default value (if valid) or 0 is returned.
/// </remarks>
/// <param name="string">The string to convert.</param>
/// <param name="default">The default value for if the value cannot be parsed.</param>
/// <returns>The specified string as a <see cref="Int32"/>.</returns>
public static int AsIntegerNonStrict(this string #string, int? #default = null)
{
int #int;
if ((!string.IsNullOrEmpty(#string)) && int.TryParse(#string, out #int))
return #int;
if (#default.HasValue)
return #default.Value;
return 0;
}
/// <summary>
/// Converts the specified string to a <see cref="bool"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="DateTime"/>.</returns>
public static bool? AsNullableBolean(this string #string)
{
bool #bool;
if ((string.IsNullOrEmpty(#string)) || !bool.TryParse(#string, out #bool))
return null;
return #bool;
}
/// <summary>
/// Converts the specified string to a <see cref="DateTime"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="DateTime"/>.</returns>
public static DateTime? AsNullableDateTime(this string #string)
{
DateTime dateTime;
if ((string.IsNullOrEmpty(#string)) || !DateTime.TryParse(#string, out dateTime))
return null;
return dateTime;
}
/// <summary>
/// Converts the specified string to a <see cref="DateTime"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="DateTime"/>.</returns>
public static TEnum? AsNullableEnum<TEnum>(this string #string) where TEnum : struct
{
TEnum #enum;
if ((string.IsNullOrEmpty(#string)) || !Enum.TryParse(#string, out #enum))
return null;
return #enum;
}
/// <summary>
/// Converts the specified string to a <see cref="Int32"/>
/// </summary>
/// <param name="string">The string to convert.</param>
/// <returns>The specified string as a <see cref="Int32"/>.</returns>
public static int? AsNullableInteger(this string #string)
{
int #int;
if ((string.IsNullOrEmpty(#string)) || !int.TryParse(#string, out #int))
return null;
return #int;
}
#endregion
}
I typically use these quite often.

In C# you can't cast string object to Int32. For example this code produces compilation error:
string a = "123.4";
int x = (int) a;
Try to use Convert class or Int32.Parse and Int32.TryParse methods if you want such functionality.
And yes, you should handle numeric casting separately, if you want to cast string to int.

string also implements IConvertible, so you can do the following.
((IConvertible)mystring).ToInt32(null);
You can even throw some extension methods around it to make it cleaner.

Related

C# Flagged Enums: how to append value

So, I have a flagged enum:
[Flags]
public enum EmailResult
{
ISPUSuccess = 1,
STSSuccess = 2
}
What I want to do is, via conditonals, set an enum var to one, the other, or both.
As in,
If (ISPU){
Result = EmailResult.ISPUSuccess
}
If (STS){
Result += EmailResult.STSSuccess
}
Like adding.. so it would effectively be
Result = EmailResult.ISPUSuccess | EmailResult.STSSuccess
You use the |= operator to set your values in an enum marked with the [Flags] attribute.
[Flags]
public enum EmailResult
{
None = 0,
ISPUSuccess = 1,
STSSuccess = 2
}
EmailResult result = EmailResult.None;
if(.... your condition ....)
result |= EmailResult.ISPUSuccess;
if( .... other condition ...)
result |= EmailResult.STSSuccess;
Console.WriteLine(result); // -> ISPUSuccess, STSSuccess
if((result & EmailResult.STSSuccess) != EmailResult.None)
..... flag is set ...
Notice that I have added another enum with value 0 to use in conditions where I need to check the current state of a particular flag.
You should use | (or |=) when working with flags. Imagine
Result = EmailResult.ISPUSuccess;
if (someCondition)
Result |= EmailResult.STSSuccess;
if (someOtherCondition)
Result |= EmailResult.STSSuccess;
if both someCondition and someOtherCondition are true you'll have a right result:
1 | 2 | 2 == 3 == 11 (binary)
in case of += however
Result = EmailResult.ISPUSuccess;
if (someCondition)
Result += EmailResult.STSSuccess;
if (someOtherCondition)
Result += EmailResult.STSSuccess;
you'll have
1 + 2 + 2 == 5 == 101 (binary)
which is wrong (please, notice that the second bit in the 101 is reset now).
I use the following generic struct for dealing with enums:
/// <summary>
/// This helper allows for easier manipulation of <see cref="Enum" /> objects with the <see cref="FlagsAttribute" />.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
MessageId = "Flags",
Justification = "This struct acts as a wrapper around Enum Flags, and relates to the term in question.")]
public struct Flags<T> : IEquatable<Flags<T>>, IEquatable<T>
{
#region Fields
private T _value;
#endregion
#region Constructors
/// <summary>
/// This constructor assures that the generic type of <typeparamref name="T" /> is first valid flags enum type.
/// </summary>
/// <exception cref="ArgumentException">Thrown if the type of <typeparamref name="T" /> is not a valid flag enum type.</exception>
[SuppressMessage("Microsoft.Usage", "CA2207:InitializeValueTypeStaticFieldsInline",
Justification = "This static constructor is not initializing any field values, instead, it is performing Type validation on the generic type T that cannot be otherwise performed.")]
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters",
MessageId = "DMFirmy.Library.Core.Utilities.Throw.InvalidArgumentIf(System.Boolean,System.String,System.String)",
Justification = "This library will not be localized.")]
static Flags()
{
var type = typeof(T);
Throw.InvalidArgumentIf(!type.IsEnum, "Flags<T> can only be used with enum types", nameof(T));
Throw.InvalidArgumentIf(type.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0, "Flags<T> can only be used with enum types with the Flags attribute", nameof(T));
}
private Flags(T value)
{
_value = value;
}
#endregion
#region Properties
private long ValueInLong
{
get { return GetLongValue(_value); }
set { _value = (T)Enum.ToObject(typeof(T), value); }
}
/// <summary>
/// Gets an enumerable collection of each of the individual flags that compose this instance.
/// </summary>
public IEnumerable<T> AllFlags
{
get
{
var values = (T[])Enum.GetValues(typeof(T));
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var f in values)
{
if (this[f]) yield return f;
}
}
}
#endregion
#region Indexers
/// <summary>
/// This indexer is used to add or check values within the stored flags.
/// </summary>
/// <param name="flags">The flags to search for.</param>
/// <returns>True if the flag is contained, flase otherwise.</returns>
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
MessageId = "flags",
Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
[IndexerName("Item")]
public bool this[T flags]
{
get
{
var flagsInLong = GetLongValue(flags);
return (ValueInLong & flagsInLong) == flagsInLong;
}
set
{
var flagsInLong = GetLongValue(flags);
if(value)
{
ValueInLong |= flagsInLong;
}
else
{
ValueInLong &= ~flagsInLong;
}
}
}
#endregion
#region Methods
/// <summary>
/// Returns true if the given <paramref name="flags" /> are completely contained.
/// </summary>
/// <param name="flags">The flags to check that the underlying value contains.</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
MessageId = "flags",
Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
public bool Contains(T flags)
{
return this[flags];
}
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
MessageId = "flags",
Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
[SuppressMessage("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider",
MessageId = "System.Convert.ToInt64(System.Object)",
Justification = "This library will not be localized.")]
private static long GetLongValue(T flags)
{
return Convert.ToInt64(flags);
}
/// <summary>
/// Indicates whether this instance and first specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>
/// <c>true</c> if <paramref name="obj" /> and this instance are the same type and represent the same value;
/// otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj)
{
// ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull
if(obj is T)
{
return Equals((T)obj);
}
if(obj is Flags<T>)
{
return Equals((Flags<T>)obj);
}
return false;
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns><c>true</c> if the current object is equal to the other parameter; otherwise, <c>false</c>.</returns>
public bool Equals(Flags<T> other)
{
return Equals(other._value);
}
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns><c>true</c> if the current object is equal to the other parameter; otherwise, <c>false</c>.</returns>
public bool Equals(T other)
{
return Equals(_value, other);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer that is the hash code for this instance.</returns>
public override int GetHashCode()
{
// ReSharper disable once NonReadonlyMemberInGetHashCode
return _value.GetHashCode();
}
/// <summary>
/// Returns the string representation of the underlying value.
/// </summary>
/// <returns>The string representation of the underlying value</returns>
public override string ToString()
{
return _value.ToString();
}
#endregion
#region Operators
/// <summary>
/// Implicit conversion from <see cref="Flags{T}" /> to the underlying <typeparamref name="T" /> value.
/// </summary>
/// <param name="flags">The <see cref="Flags{T}" /> value.</param>
/// <returns>
/// The <typeparamref name="T" /> value represented by <paramref name="flags" />
/// </returns>
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
MessageId = "flags",
Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
public static implicit operator T(Flags<T> flags)
{
return flags._value;
}
/// <summary>
/// Implicit conversion from the underlying <typeparamref name="T" /> to first <see cref="Flags{T}" /> value.
/// </summary>
/// <param name="flags">The <typeparamref name="T" /> value.</param>
/// <returns>The value of <paramref name="flags" /> as first <see cref="Flags{T}" />.</returns>
[SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms",
MessageId = "flags",
Justification = "This struct is first wrapper around Enum Flags, and relates to the term in question.")]
public static implicit operator Flags<T>(T flags)
{
return new Flags<T>(flags);
}
/// <summary>
/// Compares two <see cref="Flags{T}" /> instances to determine if they have equal values.
/// </summary>
/// <param name="first">The first <see cref="Flags{T}" />.</param>
/// <param name="second">The second <see cref="Flags{T}" />.</param>
/// <returns><c>true</c> if <paramref name="first" /> and <paramref name="second" /> are equal, <c>false</c> otherwise.</returns>
public static bool operator ==(Flags<T> first, Flags<T> second)
{
return first.Equals(second);
}
/// <summary>
/// Compares two <see cref="Flags{T}" /> instances to determine if they do not have equal values.
/// </summary>
/// <param name="first">The first <see cref="Flags{T}" />.</param>
/// <param name="second">The second <see cref="Flags{T}" />.</param>
/// <returns>
/// <c>true</c> if <paramref name="first" /> and <paramref name="second" /> are not equal, <c>false</c> if they
/// are.
/// </returns>
public static bool operator !=(Flags<T> first, Flags<T> second)
{
return !(first == second);
}
#endregion
}
This struct lets you use your flags enum like an indexed enumerable:
[Flags]
enum MyFlags
{
None = 0,
Value1 = 1,
Value2 = 2,
Value3 = 4
}
Flags<MyFlags> flags = MyFlags.Value1 | MyFlags.Value3;
bool hasValue1 = flags[MyFlags.Value1]; // true
bool hasValue2 = flags[MyFlags.Value2]; // false
bool hasValue3 = flags[MyFlags.Value3]; // true
flags[MyFlags.Value2] = true;
flags[MyFlags.Vlaue1] = false;
hasValue1 = flags[MyFlags.Value1]; // false
hasValue2 = flags[MyFlags.Value2]; // true
hasValue3 = flags[MyFlags.Value3]; // true
bool containsFlag = flags.Contains(MyFlags.Value2 | MyFlags.Value3); // true

C# Specification pattern agregate checker

I have created class that intend to check is Generic T meets all the required specifications. Need help to agregate them and return boolean value.
Here is the base specification class
/// <summary>
/// Base spec
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseSpecification<T>
{
public abstract Expression<Func<T, bool>> ToExpression();
/// <summary>
/// Meets
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public bool Meets(T entity)
{
Func<T, bool> predicate = ToExpression().Compile();
return predicate(entity);
}
}
And concrete specification that inhereits from base:
public class DeviceIsActiveSpecification : BaseSpecification<Device>
{
public override Expression<Func<Device, bool>> ToExpression()
{
//Устройство поддерживает выполнение команд (Активное)
return device => device.DeviceActivityType == DeviceActivityType.Active;
}
}
And the validator class that has to check is T meets all the cpecifications:
public class SpecificationValidator<T>
{
/// <summary>
/// Cpec list
/// </summary>
private readonly IList<BaseSpecification<T>> _specifications2Meet;
public SpecificationValidator()
{
_specifications2Meet = new List<BaseSpecification<T>>();
}
/// <summary>
/// Add cpec
/// </summary>
/// <typeparam name="TSecification"></typeparam>
/// <returns></returns>
public SpecificationValidator<T> Add<TSecification>() where TSecification : BaseSpecification<T>, new()
{
return Add(new TSecification());
}
/// <summary>
///
/// </summary>
/// <param name="specification"></param>
/// <returns></returns>
SpecificationValidator<T> Add(BaseSpecification<T> specification)
{
if (specification == null) throw new ArgumentNullException(nameof(specification));
_specifications2Meet.Add(specification);
return this;
}
/// <summary>
/// Meets all
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public bool MeetsAllSpecifications (T source)
{
??? Need help here to agregate "Meets"
}
}
Intended usage:
var validator = new SpecificationValidator<Device>()
.Add<DeviceIsActiveSpecification>()
.Add<CommunicationDeviceSpecification>()
.MeetsAllSpecifications(device);
Any help is appreciated! Thanks!
Maybe I missed something, but it seems you can simply use LINQ's All here:
public bool MeetsAllSpecifications (T source)
{
return specifications2Meet.All(spec => spec.Meets(source));
}

Achieve different SELECT and INSERT behavior on NHibernate IUserType

Is there a way to separate the Create (INSERT) behavior from the SELECT behavior.
Let's say I have a database with a column that will return a string looking like this
Predecessors = "1,3,4,5"
In my application I want to use this string like an int array by implementing an IUserType
public interface IIntArray
{
int[] Items { get; set; }
}
public class IntArray : IIntArray
{
public int[] Items { get; set; }
public IntArray(string item)
{
if(string.IsNullOrEmpty(item))
return;
Items = System.Array.ConvertAll<string, int>(item.Split(new[] {','}), int.Parse);
// for older .net versions use the code below
// Items = Array.ConvertAll<string, int>(item.ToString().Split(new[] { ',' }), delegate(string str) { return int.Parse(str); });
}
}
public class IntArrayType : IUserType
{
#region Implementation of IUserType
/// <summary>
/// Compare two instances of the class mapped by this type for persistent "equality"
/// ie. equality of persistent state
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public new bool Equals(object x, object y)
{
if (x == null && y == null) return true;
if (x == null || y == null) return false;
return x.GetType() == y.GetType();
}
/// <summary>
/// Get a hashcode for the instance, consistent with persistence "equality"
/// </summary>
public int GetHashCode(object x)
{
return x.GetHashCode();
}
/// <summary>
/// Retrieve an instance of the mapped class from a resultset.
/// Implementors should handle possibility of null values.
/// </summary>
/// <param name="rs">a IDataReader</param>
/// <param name="names">column names</param>
/// <param name="owner">the containing entity</param>
/// <returns></returns>
/// <exception cref="HibernateException">HibernateException</exception>
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var value = NHibernateUtil.String.NullSafeGet(rs, names[0]);
if (value == null || (string.IsNullOrEmpty(value.ToString())))
{
return null;
}
return new IntArray(value.ToString());
}
/// <summary>
/// Write an instance of the mapped class to a prepared statement.
/// Implementors should handle possibility of null values.
/// A multi-column type should be written to parameters starting from index.
/// </summary>
/// <param name="cmd">a IDbCommand</param>
/// <param name="value">the object to write</param>
/// <param name="index">command parameter index</param>
/// <exception cref="HibernateException">HibernateException</exception>
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (value == null)
{
((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
}
else
{
var state = (IIntArray)value;
((IDataParameter)cmd.Parameters[index]).Value = state.GetType().Name;
}
}
/// <summary>
/// Return a deep copy of the persistent state, stopping at entities and at collections.
/// </summary>
/// <param name="value">generally a collection element or entity field</param>
/// <returns>a copy</returns>
public object DeepCopy(object value)
{
return value;
}
/// <summary>
/// During merge, replace the existing (<paramref name="target" />) value in the entity
/// we are merging to with a new (<paramref name="original" />) value from the detached
/// entity we are merging. For immutable objects, or null values, it is safe to simply
/// return the first parameter. For mutable objects, it is safe to return a copy of the
/// first parameter. For objects with component values, it might make sense to
/// recursively replace component values.
/// </summary>
/// <param name="original">the value from the detached entity being merged</param>
/// <param name="target">the value in the managed entity</param>
/// <param name="owner">the managed entity</param>
/// <returns>the value to be merged</returns>
public object Replace(object original, object target, object owner)
{
return original;
}
/// <summary>
/// Reconstruct an object from the cacheable representation. At the very least this
/// method should perform a deep copy if the type is mutable. (optional operation)
/// </summary>
/// <param name="cached">the object to be cached</param>
/// <param name="owner">the owner of the cached object</param>
/// <returns>a reconstructed object from the cachable representation</returns>
public object Assemble(object cached, object owner)
{
return cached;
}
/// <summary>
/// Transform the object into its cacheable representation. At the very least this
/// method should perform a deep copy if the type is mutable. That may not be enough
/// for some implementations, however; for example, associations must be cached as
/// identifier values. (optional operation)
/// </summary>
/// <param name="value">the object to be cached</param>
/// <returns>a cacheable representation of the object</returns>
public object Disassemble(object value)
{
return value;
}
/// <summary>
/// The SQL types for the columns mapped by this type.
/// </summary>
public SqlType[] SqlTypes { get { return new[] { NHibernateUtil.String.SqlType }; } }
/// <summary>
/// The type returned by <c>NullSafeGet()</c>
/// </summary>
public Type ReturnedType { get { return typeof(IntArray); } }
/// <summary>
/// Are objects of this type mutable?
/// </summary>
public bool IsMutable { get { return false; } }
#endregion
}
In my NHibernate class I mapped to property like this
public virtual IntArray Predecessors { get; set; }
And the hbm mapping
<property name="Predecessors" type="Example.IntArrayType, Example" />
The IntArray class does it's job when reading data but when trying to put something back this doesn't work. What I would like to do is to somehow force the IntArray property to render the values of IntArray.Items to a comma separated string
string magic = string.Join(",", Predecessors.Items);
Thanks
Something like this should do the trick
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var ints = value as IntArray;
if(ints != null && ints.Items != null)
{
NHibernate.NHibernateUtil.StringClob.NullSafeSet(cmd, string.Join(", ", ints.Items), index);
}
}

Mapping System.Drawing.Color

If I don't map Color but map an object that has a Color attribute, FluentNHibernate successfully maps it to a varbinary(max). However, that's extremely inefficient given that realistically Color is just composed of 4 bytes and I am keen on improving it without using a new type to Proxy it.
Internally within Color it is made up of four properties,
long value (cast down to int to represent ARGB)
short state, indicates if this is a known & valid colour
string name, the name of the colour if known.
short knownColor a value to indicate which known colour it is
So I have attempted to map this as follows.
public ColorMapping()
{
CompositeId()
.KeyProperty(c => Reveal.Member<Color, long>("value"))
.KeyProperty(c => Reveal.Member<Color, short>("state"))
.KeyProperty(c => Reveal.Member<Color, string>("name"))
.KeyProperty(c => Reveal.Member<Color, short>("knownColor"));
}
However, on usage I get the following exception,
Class Initialization method DataContextTest.ClassInitialise threw
exception. FluentNHibernate.Cfg.FluentConfigurationException:
FluentNHibernate.Cfg.FluentConfigurationException: An invalid or
incomplete configuration was used while creating a SessionFactory.
Check PotentialReasons collection, and InnerException for more detail.
---> FluentNHibernate.Cfg.FluentConfigurationException: An invalid or
incomplete configuration was used while creating a SessionFactory.
Check PotentialReasons collection, and InnerException for more detail.
---> NHibernate.MappingException: Could not compile the mapping
document: (XmlDocument) ---> NHibernate.MappingException: Could not
determine type for:
System.Linq.Expressions.Expression1[[System.Func2[[System.Drawing.Color,
System.Drawing, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a],[System.Int64, mscorlib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]],
mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]], System.Core, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089, for columns:
NHibernate.Mapping.Column(Member).
Am I misusing Reveal? If so, how am I meant to use it?
i would map it as UserType which converts it back and forth
// in mapping
Map(x => x.Color).Column("ColorARGB").CustomType<ColorUserType>();
[Serializable]
class ColorUserType : IUserType
{
public object Assemble(object cached, object owner)
{
return DeepCopy(cached);
}
public object DeepCopy(object value)
{
return value;
}
public object Disassemble(object value)
{
return DeepCopy(value);
}
bool IUserType.Equals(object x, object y)
{
var colorX = x as Color;
var colorY = y as Color;
return colorX == null ? colorY = null : colorX.ToArgb() == colorY.ToArgb();
}
public virtual int GetHashCode(object x)
{
var colorX = (Color)x;
return (colorX != null) ? colorX.ToArgb() : 0;
}
public bool IsMutable { get { return false; } }
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
return Color.FromArgb((int)NHibernateUtil.Int32.Get(rs, names[0]));
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
NHibernateUtil.Int32.Set(cmd, ((Color)value).ToArgb(), index);
}
public object Replace(object original, object target, object owner)
{
return original;
}
public Type ReturnedType { get { return typeof(Color); } }
public SqlType[] SqlTypes { get { return new []{ SqlTypeFactory.Int32 }; } }
}
I went with an ICompositeUserType in the end.
Code as follows,
public class ColorType : ICompositeUserType
{
/// <summary>
/// Get the value of a property
/// </summary>
/// <param name="component">an instance of class mapped by this "type"</param>
/// <param name="property"/>
/// <returns>
/// the property value
/// </returns>
public object GetPropertyValue(object component, int property)
{
var color = (Color) component;
if (property == 0)
{
return color.ToArgb();
}
return (int) color.ToKnownColor();
}
/// <summary>
/// Set the value of a property
/// </summary>
/// <param name="component">an instance of class mapped by this "type"</param>
/// <param name="property"/>
/// <param name="value">the value to set</param>
public void SetPropertyValue(object component, int property, object value)
{
throw new InvalidOperationException("Color is immutable");
}
/// <summary>
/// Compare two instances of the class mapped by this type for persistence
/// "equality", ie. equality of persistent state.
/// </summary>
/// <param name="x"/><param name="y"/>
/// <returns/>
public new bool Equals(object x, object y)
{
return ReferenceEquals(x, y) ||
x != null && y != null &&
object.Equals(x, y);
}
/// <summary>
/// Get a hashcode for the instance, consistent with persistence "equality"
/// </summary>
public int GetHashCode(object x)
{
return x == null
? 0
: x.GetHashCode();
}
/// <summary>
/// Retrieve an instance of the mapped class from a IDataReader. Implementors
/// should handle possibility of null values.
/// </summary>
/// <param name="dr">IDataReader</param>
/// <param name="names">the column names</param>
/// <param name="session"/>
/// <param name="owner">the containing entity</param>
/// <returns/>
public object NullSafeGet(IDataReader dr, string[] names,
ISessionImplementor session, object owner)
{
var argb = (int?) NHibernateUtil.Int32.NullSafeGet(dr, names[0]);
var knownColor = (int?) NHibernateUtil.Int32.NullSafeGet(dr, names[1]);
return knownColor != null
? Color.FromKnownColor((KnownColor) knownColor.Value)
: Color.FromArgb(argb.Value);
}
/// <summary>
/// Write an instance of the mapped class to a prepared statement.
/// Implementors should handle possibility of null values.
/// A multi-column type should be written to parameters starting from index.
/// If a property is not settable, skip it and don't increment the index.
/// </summary>
/// <param name="cmd"/>
/// <param name="value"/>
/// <param name="index"/>
/// <param name="settable"/>
/// <param name="session"/>
public void NullSafeSet(IDbCommand cmd, object value, int index,
bool[] settable, ISessionImplementor session)
{
var color = (Color) value;
if (color.IsKnownColor)
{
((IDataParameter) cmd.Parameters[index]).Value = DBNull.Value;
((IDataParameter) cmd.Parameters[index + 1]).Value = (int) color.ToKnownColor();
}
else
{
((IDataParameter) cmd.Parameters[index]).Value = color.ToArgb();
((IDataParameter) cmd.Parameters[index + 1]).Value = DBNull.Value;
}
}
/// <summary>
/// Return a deep copy of the persistent state, stopping at entities and at collections.
/// </summary>
/// <param name="value">generally a collection element or entity field</param>
/// <returns/>
public object DeepCopy(object value)
{
return value;
}
/// <summary>
/// Transform the object into its cacheable representation.
/// At the very least this method should perform a deep copy.
/// That may not be enough for some implementations,
/// method should perform a deep copy. That may not be enough for
/// some implementations, however; for example, associations must
/// be cached as identifier values. (optional operation)
/// </summary>
/// <param name="value">the object to be cached</param>
/// <param name="session"/>
/// <returns/>
public object Disassemble(object value, ISessionImplementor session)
{
return value;
}
/// <summary>
/// Reconstruct an object from the cacheable representation.
/// At the very least this method should perform a deep copy. (optional operation)
/// </summary>
/// <param name="cached">the object to be cached</param>
/// <param name="session"/>
/// <param name="owner"/>
/// <returns/>
public object Assemble(object cached, ISessionImplementor session, object owner)
{
return cached;
}
/// <summary>
/// During merge, replace the existing (target) value in the entity we are merging to
/// with a new (original) value from the detached entity we are merging. For immutable
/// objects, or null values, it is safe to simply return the first parameter. For
/// mutable objects, it is safe to return a copy of the first parameter. However, since
/// composite user types often define component values, it might make sense to recursively
/// replace component values in the target object.
/// </summary>
public object Replace(object original, object target, ISessionImplementor session, object owner)
{
return original;
}
/// <summary>
/// Get the "property names" that may be used in a query.
/// </summary>
public string[] PropertyNames { get { return new[] {"Argb", "KnownColor"}; } }
/// <summary>
/// Get the corresponding "property types"
/// </summary>
public IType[] PropertyTypes
{
get
{
return new IType[]
{
NHibernateUtil.Int32, NHibernateUtil.Int32
};
}
}
/// <summary>
/// The class returned by NullSafeGet().
/// </summary>
public Type ReturnedClass { get { return typeof (Color); } }
/// <summary>
/// Are objects of this type mutable?
/// </summary>
public bool IsMutable { get { return false; } }
}

C# Anonymous types cannot be assigned to -- it is read only

What is wrong with this code-snippet?
class Program
{
static void Main(string[] args)
{
var obj = new { Name = "A", Price = 3.003 };
obj.Name = "asdasd";
obj.Price = 11.00;
Console.WriteLine("Name = {0}\nPrice = {1}", obj.Name, obj.Price);
Console.ReadLine();
}
}
I am getting the following errors:
Error 5 Property or indexer 'AnonymousType#1.Name' cannot be assigned to -- it is read only .....\CS_30_features.AnonymousTypes\Program.cs 65 13 CS_30_features.AnonymousTypes
Error 6 Property or indexer 'AnonymousType#1.Price' cannot be assigned to -- it is read only .....\CS_30_features.AnonymousTypes\Program.cs 66 13 CS_30_features.AnonymousTypes
How to re-set values into an anonymous type object?
Anonymous types in C# are immutable and hence do not have property setter methods. You'll need to create a new anonmyous type with the values
obj = new { Name = "asdasd", Price = 11.00 };
Anonymous types are created with read-only properties. You can't assign to them after the object construction.
From Anonymous Types (C# Programming Guide) on MSDN:
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to first explicitly define a type.
Anonymous types provide a convenient way to encapsulate a set of
read-only properties into a single
object without having to first
explicitly define a type. The type
name is generated by the compiler and
is not available at the source code
level. The type of the properties is
inferred by the compiler. The
following example shows an anonymous
type being initialized with two
properties called Amount and Message.
http://msdn.microsoft.com/en-us/library/bb397696.aspx
Use ExpandoObject instead since it supports updating/adding new properties after object creation (it has been around since since C# 4).
Note that it is important to declare the object using the keyword dynamic (instead of var)
using System.Dynamic;
dynamic person = new ExpandoObject();
person.FirstName = "John";
person.LastName = "Doe";
/// <summary>
/// Of 8 bytes.
/// A structure which represents an:
/// <see cref="System.Object"/>, <see cref="System.Array"/> or <see cref="System.String"/>.
/// </summary>
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit, Size = 8)]
public struct Invariant
{
[System.Runtime.InteropServices.FieldOffset(0)]
public System.ValueType Value;
[System.Runtime.InteropServices.FieldOffset(0)]
public System.Array Array;
[System.Runtime.InteropServices.FieldOffset(0)]
public object Object;
[System.Runtime.InteropServices.FieldOffset(0)]
public string String;
/// <summary>
/// Used to interpret the address/memory of object which can be thought of as IntPtr*
/// Remember to deference the type 1 time to inspect the memory where ref object points to.
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
public System.Span<TType> GetSpan<TType>(int index, int length) => System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref System.Runtime.CompilerServices.Unsafe.Add(ref System.Runtime.CompilerServices.Unsafe.As<object, TType>(ref Object), index), length);
/// <summary>
/// Get a <see cref="System.IntPtr"/> which points to the address of <see cref="Object"/>
/// </summary>
/// <returns></returns>
public System.IntPtr ToPointer() => GetSpan<System.IntPtr>(0, 1)[0] + System.IntPtr.Size + System.IntPtr.Size; //Syncbloc, Rtti
/// <summary>
///
/// </summary>
/// <returns></returns>
public bool IsAligned() => (ulong)ToPointer() % (ulong)System.IntPtr.Size == 0;
/// <summary>
/// Allowing one to set the <see cref="System.Type"/> of <see cref="Object"/>
/// </summary>
public System.Type Type
{
set
{
System.Runtime.InteropServices.Marshal.WriteIntPtr(GetSpan<System.IntPtr>(0, 1)[0], value.TypeHandle.Value);
//System.Runtime.CompilerServices.Unsafe.AsRef(System.Runtime.CompilerServices.Unsafe.As<object, System.IntPtr>(ref Object)) = value.TypeHandle.Value;
//System.Runtime.CompilerServices.Unsafe.AsRef(GetSpan<System.IntPtr>(0, 1)[0]) = value.TypeHandle.Value;
}
}
}
/// <summary>
/// A single value
/// Will implicitly convert to <see cref="Invariant"/>
/// </summary>
/// <typeparam name="T"></typeparam>
public ref struct Invariant<T>
{
public static System.RuntimeTypeHandle TypeHandle => typeof(T).TypeHandle;
public static System.IntPtr ToPointer(ref T t)
{
System.IntPtr rtti = System.Runtime.CompilerServices.Unsafe.As<T, System.IntPtr>(ref t);
//rtti = System.Runtime.InteropServices.Marshal.ReadIntPtr(rtti, 0);
return rtti;
}
/// <summary>
/// The value
/// </summary>
public T Value;
/// <summary>
/// Implicit create <see cref="Invariant"/>
/// </summary>
/// <param name="src"></param>
public static implicit operator Invariant(Invariant<T> src) => new Invariant() { Object = src.Value };
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static T Emplace(ref Invariant invariant, bool writeHeader) => Emplace(invariant.ToPointer(), writeHeader);
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static T Emplace(ref Invariant invariant) => Emplace(invariant.ToPointer(), false == System.Type.GetTypeFromHandle(TypeHandle).IsValueType);//Might need to read the void* in the spann which is is different places depending on the runtime.
/// <summary>
/// Emplace the value initializing the Object header and TypeHandle.
/// </summary>
/// <param name="bufferPtr"></param>
/// <returns></returns>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static T Emplace(System.IntPtr bufferPtr, bool writeHeader = true)
{
var dataPointer = bufferPtr + 1;
//New way
if (writeHeader) System.Runtime.CompilerServices.Unsafe.AsRef(in bufferPtr) = System.IntPtr.Zero;
System.Runtime.CompilerServices.Unsafe.AsRef(in dataPointer) = typeof(T).TypeHandle.Value;
//Old way
//if (writeHeader) System.Runtime.InteropServices.Marshal.WriteIntPtr(bufferPtr, System.IntPtr.Zero); //Object Header
//System.Runtime.InteropServices.Marshal.WriteIntPtr(dataPointer, typeof(T).TypeHandle.Value);
return System.Runtime.CompilerServices.Unsafe.As<System.IntPtr, T>(ref dataPointer); //Pointer to the method table pointer
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static T Emplace(ref T t, bool writeHeader = true) => Emplace(System.Runtime.CompilerServices.Unsafe.AsRef(in System.Runtime.CompilerServices.Unsafe.As<T, System.IntPtr>(ref t)), writeHeader);
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static T Emplace(ref T t) => Emplace(ref t, false == System.Type.GetTypeFromHandle(TypeHandle).IsValueType);
/// <summary>
/// Useful when ref t has been Emplaced
/// </summary>
/// <param name="expression"></param>
/// <param name="t"></param>
/// <param name="arguments"></param>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static void Construct(System.Linq.Expressions.Expression<System.Action> expression, ref T t, params object[] arguments)
{
//figure out which constructorInfo
System.Linq.Expressions.NewExpression newExpression = expression.Body as System.Linq.Expressions.NewExpression;
//newExpression.Arguments
//DeclaringType should equal typeof(T)
//typeof(T).GetConstructor(System.Array.Empty<System.Type>()).Invoke(t, arguments);
//don't read the object returned here its on the stack and boxed refer to t
if (null == arguments) arguments = System.Array.Empty<object>();
newExpression.Constructor.Invoke(t, arguments);
//Could get paramters from expression
var instantiator = System.Linq.Expressions.Expression.Lambda/*<System.Func<T>>*/(newExpression).Compile();
instantiator.Method.Invoke(t, arguments);
}
//[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
//public unsafe static T Alloc(System.Span<byte> bytes) => Alloc((System.IntPtr)System.Runtime.CompilerServices.Unsafe.AsPointer(ref bytes.GetPinnableReference()));
//Could be exposed from a static Construct<T>(ref T) method but which constructor to invoke?
//Could also accept an Expression and use the expression to build a delegate
//Alloc(()=>new Whatever(1,2,3,"4"));
//When you have the expression the call to the correct MethodInfo (constructor) is already performed via overload resolution.
//
//private static unsafe class Constructor
//{
// private static readonly delegate*<T, void> ConstructorHandle;
// static Constructor()
// {
// System.Type type = typeof(T);
// System.Reflection.ConstructorInfo constructorInfo = type.GetConstructor(System.Array.Empty<System.Type>());
// Constructor.ConstructorHandle = (delegate*<T, void>)constructorInfo.MethodHandle.GetFunctionPointer();
// }
// [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
// internal static void Invoke(T returnObject)
// {
// Constructor.ConstructorHandle(returnObject);
// }
//}
/// <summary>
/// Creates a <see cref="System.Span{T}"/>
/// </summary>
/// <returns></returns>
public System.Span<T> GetSpan() => System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref Value, 1);
/// <summary>
/// Create a <see cref="System.Span{TType}"/>
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
public System.Span<TType> GetSpan<TType>(int index, int length) => System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref System.Runtime.CompilerServices.Unsafe.Add(ref System.Runtime.CompilerServices.Unsafe.As<T, TType>(ref Value), index), length);
}
/// <summary>
/// Provides extensions useful for <see cref="System.Span{T}"/>
/// </summary>
public static class SpanExtensions
{
/// <summary>
/// Pointer to the first element
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="span"></param>
/// <returns></returns>
public static System.IntPtr ToPointer<T>(this System.Span<T> span)
{
//ptr to struct to interior ptr
ref T pp = ref span[0];
ref byte b = ref System.Runtime.CompilerServices.Unsafe.As<T, byte>(ref pp);
//Interior pointer layout and size may vary with such
//Object header is 24 bytes and 1 more pointer for the interior ptr itself
b = ref System.Runtime.CompilerServices.Unsafe.Add(ref b,(System.IntPtr)(-System.IntPtr.Size * 4));
//from bite to pointer
ref System.IntPtr ptrSpan = ref System.Runtime.CompilerServices.Unsafe.As<byte, System.IntPtr>(ref b);
return ptrSpan;
}
public static int ReadLength(ref System.IntPtr ptr) => System.Runtime.InteropServices.Marshal.ReadInt32(ptr, System.IntPtr.Size);
public static System.Span<T> RecoverSpan<T>(System.IntPtr ptr)
{
//Because of reloc on the stack 1 must keep 2 pts, 1 to the length and 1 to the last element
var pb = ptr + (System.IntPtr.Size * 4);
ref byte reverse = ref System.Runtime.CompilerServices.Unsafe.As<System.IntPtr, byte>(ref pb);
ref T pp = ref System.Runtime.CompilerServices.Unsafe.As<byte, T>(ref reverse);
System.Span<T> span = System.Runtime.InteropServices.MemoryMarshal.CreateSpan(ref pp, System.Runtime.InteropServices.Marshal.ReadInt32(ptr, System.IntPtr.Size));
return span;
}

Categories

Resources