enum depending on Type T - c#

I have a generic class that needs to limit an enum depending on the type defined:
public enum ConditionOperatorsString { None, Like, Equal }
public enum ConditionOperatorsDate { None, Equal, BeforeThan, AfterThan }
public class Condition<T>
{
public T Value { get; set; }
public ConditionOperatorsString Operator { get; set; }
public Condition(T Value, ConditionOperatorsString Operator)
{
this.Value = Value;
this.Operator = Operator;
}
}
Now the problem is that i want the Operator type be dependant on T so when:
Condition<string> CStr= new Condition<string>(string.Empty, ConditionOperatorsString.None)
Condition<DateTime> CStr= new Condition<DateTime>(DateTime.Now, ConditionOperatorsDate.None)
How do I define the class Condition for that? I thought of an interface but enums don't inherit from interfaces.

There's no good way to do what you're trying to do without having, in your constructor something like:
if (typeof(T) == typeof(string) &&
typeof(Operator) != typeof(ConditionOperatorsString))
{
throw new Exception("Invalid conditionoperators value);
}
That's really not very useful, since you have to know, ahead of time, all the different possibilities for T.
What you could do, is something like this:
public abstract class ComparableBase<T,K>
{
public T Value { get; protected set; }
public K ConditionOperator { get; protected set; }
// public abstract bool IsMatch(T other); // Is this required?
protected ComparableBase(T value, K op)
{
this.Value = value;
this.ConditionOperator = op;
}
}
public enum ComparableOperator { None, Equal, Less, Greater }
public enum LikeOrEqualOperator { None, Like, Equal }
public class ComparableCondition<T> : ComparableBase<T,ComparableOperator>
{
public ComparableCondition(T value, ComparableOperator op):base(value, op)
{
}
}
public class LikeOrEqualCondition<T> : ComparableBase<T, LikeOrEqualOperator>
{
public LikeOrEqualCondition(T value, LikeOrEqualOperator op):base(value, op)
{
}
}
then you can declare
var condition1 = new LikeOrEqualCondition<string>("hi", LikeOrEqualOperator.Equal);
Do you need to have an IsMatch? Or is this to display the selected filter, without actually implementing it.
If you do, things are a teensy bit more complicated...

Could the enum type just be another generic parameter e.g.
public enum ConditionOperatorsString { None, Like, Equal }
public enum ConditionOperatorsDate { None, Equal, BeforeThan, AfterThan }
public class Condition<T, TEnum>
{
public T Value { get; set; }
public TEnum Operator { get; set; }
public Condition(T Value, TEnum Operator)
{
this.Value = Value;
this.Operator = Operator;
}
}
Might need more info though, not 100% sure how this is meant to actually fit in with the code that will make use of it

You should include the enum type as a template parameter.
public class Condition<TValue, TOperator>
{
public TValue Value { get; private set; }
public TOperator Operator { get; private set; }
private Condition(TValue val, TOperator op)
{
Value = val;
Operator = op;
}
}
It would be nice to be able to add where TOperator : Enum, but I'm pretty sure the compiler doesn't allow that.

Thanks for the answers.
I wanted to avoid to have more than one class but apparently it cannot be done. Based on the last comment from silky i got to a similar sollution as nader.
Not the optimal one but it does the trick of restricting the enum, the con is that the client has to be aware that there are n classes:
public abstract class ConditionBase<T, E>
{
public T Value { get; set; }
public E Operator { get; set; }
protected ConditionBase(T Value, E Operator)
{
this.Value = Value;
this.Operator = Operator;
}
}
public enum ConditionOperatorsString { None, Like, Equal }
public class ConditionString : ConditionBase<string, ConditionOperatorsString>
{
public ConditionString(String Value, ConditionOperatorsString Operator) : base(Value, Operator) { }
}
public enum ConditionOperatorsDate { None, Like, BeforeThan, AfterThan }
public class ConditionDate : ConditionBase<DateTime?, ConditionOperatorsDate>
{
public ConditionDate(DateTime? Value, ConditionOperatorsDate Operator) : base(Value, Operator) { }
}
Client use:
ConditionString StrCond = new ConditionString(string.Empty, ConditionOperatorsString.None);
ConditionDate DateCond = new ConditionDate(DateTime.MinValue, ConditionOperatorsDate.None);
I wanted to be able to use from the client something like:
ConditionGeneric StrCond = new ConditionGeneric(string.Empty, ConditionOperatorsString.None);
ConditionGeneric DateCond = new ConditionGeneric(DateTime.MinValue, ConditionOperatorsDate.None);
ConditionGeneric InvalidStrCond = new ConditionGeneric(string.Empty, ConditionOperatorsDate.None);
ConditionGeneric InvalidDateCond = new ConditionGeneric(DateTime.MinValue, ConditionOperatorsString.None);

If you make your field
public ValueType Operator { get; set; }
It'll work, but I'm not sure if that's what you want ...
-- Edit
What are you trying to do, anyway? C# has operator overloading, so perhaps that could be of use, instead?

Related

Convert a class that has a string property into another class with typed property value

Having the following classes:
public class DeviceParameter
{
public string Key { get; set; }
public Guid DeviceId { get; set; }
public string Value { get; set; }
}
A device can have a lot of parameters, of different types, but they are all stored in the database as strings.
public abstract class DeviceValueTypedParameter<TValue>
{
public string CodeName { get; }
public TValue Value { get; set; }
public Guid DeviceId { get; set; }
public DeviceValueTypedParameter(string codeName)
{
this.CodeName = codeName;
}
}
DeviceValueTypedParameter is an abstraction, to have a typed value (TValue) used on C# of the parameter value, instead of using the string that we get from the database. There is no heritance between DeviceValueTypedDeviceParameter and DeviceParameter because I want to make the conversion from TValue to string by composition.
public class ArmingStatusParameter : DeviceValueTypedParameter<ArmingStatuses>
{
public const string CODE_NAME = "ArmingStatus";
public ArmingStatusParameter() : base(CODE_NAME)
{
}
}
public enum ArmingStatuses
{
Unknown,
Armed,
Disarmed,
}
ArmingStatusParameter is an example of a typed Parameter that can exist, where the value is an Enum of ArmingStatuses. Other types that can exist are DateTimes, int32, double, etc.
I've already accomplished the conversion from Typed value to string, but now I'm struggling how to properly do the conversion from string to Typed value.
Tried different approaches:
Implicit or Explicit conversion
Extension method
Converter classes for each type that exists
Generic converter class based on TValue type
Option 1: is easy to implement, but violates the POCO of
ArmingStatusParameter. People can forget to implement the implicit/explicit operators and errors will only happen at compile time.
Option 2: violates the Interface segregation principle (ISP), since is needed to access directly the conversion.
Option 3: it works, but people will have to create a lot of classes and the code will be too verbose. For each different parameter, is needed to instance a new {X}TypedParameterConverter.
Option 4: seems the best option, but I am having troubles "in making it work"
I was thinking about something like this:
public interface IDeviceValueTypedParameterConverter
{
bool TryConvert<T, TValue>(DeviceParameter deviceParameter,
DeviceValueTypedParameter<TValue> deviceValueTypedParameter)
where T : DeviceValueTypedParameter<TValue>;
}
public class DeviceValueTypedParameterConverter : IDeviceValueTypedParameterConverter
{
public bool TryConvert<T, TValue>(DeviceParameter inputParameter,
DeviceValueTypedParameter<TValue> outputParameter)
where T : DeviceValueTypedParameter<TValue>
{
bool result = true;
if (inputParameter == null)
{
throw new NullReferenceException($"DeviceValueTypedParameter:'{typeof(T)}' must be initialized first");
}
if (inputParameter.Value is int)
{
result = int.TryParse(inputParameter.Value, out int temp);
outputParameter.Value = (TValue)temp;
}
else if (inputParameter.Value is Enum)
{
// some other code to convert the Enum's
}
// more else ifs one for each type
// (...)
else
{
result = false;
}
outputParameter.DeviceId = inputParameter.DeviceId;
return result;
}
}
Issues:
All the Ifs gives me a warning saying: "The given expression is never of the provided".
Can't make the cast (TValue). It says can't convert int to TValue. The only solution is creating value via reflection?
Here is my attempt to make this work - I am not sure if it violates some details you did not explain (or did explain). Since out parameters can't use polymorphism, I created an interface to represent the common functions across the typed parameter base class. Since there are no static virtual methods, I used object methods and created a result object that will is used if the conversion is possible.
I see no reason for the conversion method to have multiple instances or need an interface, so I created it as a single static method. I used an enum to capture the type of conversion needed for the parameter accessible from the passed in type, and had to do a tricky conversion through object to handle assignment to the out parameter value field, since C# has no type switching capability for assignments. Note this could cause a runtime error if the IsPossible method doesn't properly filter all cases and the ChangeType fails.
public enum ValueParseTypes {
Enum,
DateTime,
Int
}
public interface IDeviceValueTypedDeviceParameter<TValue> {
string CodeName { get; }
TValue Value { get; set; }
Guid DeviceId { get; set; }
ValueParseTypes ParseType { get; set; }
bool IsPossibleValue(DeviceParameter aValue);
}
public abstract class DeviceValueTypedDeviceParameter<TValue> : IDeviceValueTypedDeviceParameter<TValue> {
public string CodeName { get; }
public TValue Value { get; set; }
public Guid DeviceId { get; set; }
public ValueParseTypes ParseType { get; set; }
public DeviceValueTypedDeviceParameter(string codeName, ValueParseTypes parseType) {
this.CodeName = codeName;
this.ParseType = parseType;
}
public virtual bool IsPossibleValue(DeviceParameter aValue) => false;
}
public class ArmingStatusParameter : DeviceValueTypedDeviceParameter<ArmingStatuses> {
public const string CODE_NAME = "ArmingStatus";
public ArmingStatusParameter() : base(CODE_NAME, ValueParseTypes.Enum) {
}
static HashSet<string> ArmingStatusesNames = Enum.GetNames(typeof(ArmingStatuses)).ToHashSet();
public override bool IsPossibleValue(DeviceParameter aValue) => ArmingStatusesNames.Contains(aValue.Value);
}
public enum ArmingStatuses {
Unknown,
Armed,
Disarmed,
}
public class PoweredOnStatusParameter : DeviceValueTypedDeviceParameter<DateTime> {
public const string CODE_NAME = "PoweredOn";
public PoweredOnStatusParameter() : base(CODE_NAME, ValueParseTypes.DateTime) {
}
public override bool IsPossibleValue(DeviceParameter aValue) => DateTime.TryParse(aValue.Value, out _);
}
public class VoltageStatusParameter : DeviceValueTypedDeviceParameter<int> {
public const string CODE_NAME = "PoweredOn";
public VoltageStatusParameter() : base(CODE_NAME, ValueParseTypes.Int) {
}
public override bool IsPossibleValue(DeviceParameter aValue) => Int32.TryParse(aValue.Value, out _);
}
public static class DeviceValueTypedParameterConverter {
public static bool TryConvert<TValue>(DeviceParameter inputParameter, IDeviceValueTypedDeviceParameter<TValue> outputParameter)
where TValue : struct {
if (inputParameter == null)
throw new ArgumentNullException(nameof(inputParameter));
else if (outputParameter == null)
throw new ArgumentNullException(nameof(outputParameter));
bool result = false;
if (outputParameter.IsPossibleValue(inputParameter)) {
outputParameter.DeviceId = inputParameter.DeviceId;
switch (outputParameter.ParseType) {
case ValueParseTypes.Enum:
if (Enum.TryParse(inputParameter.Value, out TValue typedValue)) {
outputParameter.Value = typedValue;
result = true;
}
break;
case ValueParseTypes.DateTime:
if (DateTime.TryParse(inputParameter.Value, out var dtValue)) {
outputParameter.Value = (TValue)Convert.ChangeType(dtValue, typeof(TValue));
result = true;
}
break;
case ValueParseTypes.Int:
if (Int32.TryParse(inputParameter.Value, out var intValue)) {
outputParameter.Value = (TValue)Convert.ChangeType(intValue, typeof(TValue));
result = true;
}
break;
}
}
return result;
}
}
Now you can use it like so:
var as_tv = new DeviceParameter() {
Key = "testkey",
DeviceId = new Guid(),
Value = "Armed"
};
var asp = new ArmingStatusParameter();
if (DeviceValueTypedParameterConverter.TryConvert<ArmingStatuses>(as_tv, asp)) {
// work with asp
}
var po_tv = new DeviceParameter() {
Key = "testkey2",
DeviceId = new Guid(),
Value = "4/15/2019 17:36"
};
var pop = new PoweredOnStatusParameter();
if (DeviceValueTypedParameterConverter.TryConvert<DateTime>(po_tv, pop)) {
// work with pop
}
var v_tv = new DeviceParameter() {
Key = "testkey3",
DeviceId = new Guid(),
Value = "17"
};
var vp = new VoltageStatusParameter();
if (DeviceValueTypedParameterConverter.TryConvert<int>(v_tv, vp)) {
// work with vp
}

Assign additional attributes to types like int, float for reflection purposes

I am trying to automate the display (gathering via reflection) of my variables which are located in specific scripts in Unity. The trouble is assigning custom values (for example: "string DisplayName", "bool DisplayMe", "bool WriteMe" etc.). When it comes to my custom classes I understand how I would do it, but I would like to avoid remaking types like float, string, int etc. for this purpose.
For example, let's say I have:
public class myBaseClass
{
public string Name = "Display Name";
public bool AmReadable = true;
public bool AmWritable = true;
}
Then:
public class myDoubleFloat: myBaseClass
{
public float ValueFirst;
public float ValueSecond;
}
So in some scripts in Unity I define it:
public class SomeScriptOnGameObject : MonoBehaviour
{
public myDoubleFloat myFirstVariable{get; set;}
public float mySecondVariable{get; set;}
}
So later on with reflection I can check whether "myFirstVariable" should be read, it's display name etc. - while for "mySecondVariable" I cannot perform this check. How do I go about this without reinventing the wheel and making a class for each of these types like float, string, int, List etc.?
You can define a generic wrapper:
public class MyProperty<T>
{
private T _value;
public T Get() => _value;
public T Set(T newValue) => _value = newValue;
public string Name { get; set; }
public bool AmReadable { get; set; }
public bool AmWritable { get; set; }
}
And make your properties's getters and setter to map to some backing fields of type MyProperty<T>:
public class SomeScriptOnGameObject : MonoBehaviour
{
private MyProperty<MyDoubleFloat> _myFirstVariable;
private MyProperty<float> _mySecondVariable;
public MyDoubleFloat MyFirstVariable
{
get => _myFirstVariable.Get();
set => _myFirstVariable.Set(value);
}
public float MySecondVariable
{
get => _mySecondVariable.Get();
set => _mySecondVariable.Set(value);
}
public SomeScriptOnGameObject()
{
_myFirstVariable = new MyProperty<MyDoubleFloat>
{
//configuration
};
_mySecondVariable = new MyProperty<float>
{
//configuration
};
}
}
If you want to be fancy you can even add an implicit operator to get rid of Get() and make any T assignable from MyProperty<T>:
public class MyProperty<T>
{
private T _value;
public T Set(T newValue) => _value = newValue;
public string Name { get; set; }
public bool AmReadable { get; set; }
public bool AmWritable { get; set; }
public static implicit operator T(MyProperty<T> myProperty) =>
myProperty != null ? myProperty._value : default;
}
And:
public MyDoubleFloat MyFirstVariable
{
get => _myFirstVariable;
set => _myFirstVariable.Set(value);
}
Wrapping value objects (int, float, etc.) is probably not the best approach. Besides the additional complexity (and possibility for bugs), you are now bloating the memory footprint of your game.
(I'm intentionally avoiding newer C# syntax in these examples)
Since you are already in a reflection context, instead of wrapping your value objects, I'd suggest an attribute-based approach. For example:
public class SomeScriptOnGameObject
{
[DisplayName("First Variable"), Writable]
public float FirstVariable { get; set; }
[DisplayName("Second Variable")]
public float SecondVariable { get; set; }
[DisplayName("Some Field")]
public float Field;
public float FieldWithNoAttributes;
}
This has the advantage of keeping the metadata of the fields in the metadata, instead of carrying around a copy of everything with every instance you create.
The actual attributes are easy to create, also. I'll start with the simplest one, WritableAttribute:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class WritableAttribute : Attribute
{
}
This empty class is all that's needed to mark a field or property as "Writable". The AttributeUsage marks this as only valid on fields and properties (not, for example, a class).
The other attribute, DisplayName, is only slightly more complex:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class DisplayNameAttribute : Attribute
{
public string DisplayName { get; private set; }
public DisplayNameAttribute(string displayName)
{
DisplayName = displayName;
}
}
The main difference is the constructor with the displayName argument, and the DisplayName property. This forces the compiler to expect an argument to the attribute.
With some extension methods, you can make things very clean:
public static class AttributeExtensions
{
public static bool IsWritable(this MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(WritableAttribute)).Any();
}
public static string DisplayName(this MemberInfo memberInfo)
{
var displayNameAttribute =
memberInfo.GetCustomAttributes(typeof(DisplayNameAttribute))
.FirstOrDefault() as DisplayNameAttribute;
return displayNameAttribute == null ? null : displayNameAttribute.DisplayName;
}
public static PropertyInfo Property<T>(this T _, string propertyName)
{
return typeof(T).GetProperty(propertyName);
}
public static FieldInfo Field<T>(this T _, string fieldName)
{
return typeof(T).GetField(fieldName);
}
}
(Since you mentioned you are already using reflection, you might not need the last two methods there.)
Finally, a simple XUnit test to demonstrate:
public class UnitTest1
{
[Fact]
public void Test1()
{
var obj = new SomeScriptOnGameObject();
Assert.True(obj.Property("FirstVariable").IsWritable());
Assert.False(obj.Property("SecondVariable").IsWritable());
Assert.False(obj.Field("Field").IsWritable());
Assert.Equal("First Variable", obj.Property("FirstVariable").DisplayName());
Assert.Equal("Second Variable", obj.Property("SecondVariable").DisplayName());
Assert.Equal("Some Field", obj.Field("Field").DisplayName());
Assert.Null(obj.Field("FieldWithNoAttributes").DisplayName());
}
}

Generic Value Object in C#

I have a VO class that contains several variables incl. a variable that can be of different types and to prevent casting later on I wonder if I can make that class generic.
public class InputVO<T>
{
public bool isEnabled;
public T value;
}
Then I want to create an array of InputVOs and a method to get a typed InputVO...
public InputVO[] Inputs { get; private set; }
public InputVO GetInput(InputType type)
{
return Inputs[(int)type];
}
How do I go about defining the array and the GetInput method so that they work with the generic InputVO? (The InputType type argument is an enum. Shouldn't really matter here, I think).
Generic type parameters are fixed at compile-time.
Whenever you use InputVO, that type parameter needs to be filled in.
public InputVO<T1>[] Inputs { get; private set; }
But what you seem to want is different InputVO objects for each datatype, and to be able to retrieve them by type at runtime:
// Base class for all InputVOs
public abstract InputVOBase
{
public bool isEnabled;
}
// InputVO for a specific data-type
public class InputVO<T> : InputVOBase
{
public T Value;
}
Now you can use a dictionary from Type to InputVOBase.
// One InputVO per datatype
public Dictionary<Type, InputVOBase> AllInputs { get; private set; }
// Return the VO for type T, or null
public InputVO<T> GetInput<T>()
{
InputVOBase vo = AllInputs[typeof(T)];
return (vo as InputVO<T>);
}
You cannot create an array of a generic class without specifying the type. However, as you have control over the base type, you can make that implement a non generic interface and have a collection of that instead:
//Empty interface
public interface IInputVO { }
//Your generic class now implements the interface
public class InputVO<T> : IInputVO
{
public bool isEnabled { get; set; }
public T Value { get; set; }
}
So now your array is of the interface type IInputVO:
IInputVO[] inputs =
{
new InputVO<int>(),
new InputVO<string>(),
new InputVO<SomeClass>(),
};
Cleaned up solution a bit. Mainly you need to collect your values in a dictionary.
void Main()
{
var a = new InputVO<string> { Value = "test" };
var b = new InputVO<int> { Value = 5 };
Inputs.Add(typeof(string), a);
Inputs.Add(typeof(int), b);
var x = GetInput<string>();
Console.WriteLine(x.Value);
var y = GetInput<int>();
Console.WriteLine(y.Value);
}
public abstract class InputVOBase
{
public bool isEnabled;
}
public class InputVO<T> : InputVOBase
{
public T Value;
}
public Dictionary<Type, InputVOBase> Inputs = new Dictionary<Type, InputVOBase>();
public InputVO<T> GetInput<T>()
{
return Inputs[typeof(T)] as InputVO<T>;
}
Thanks for the tips anyone! Phew, since there's no way getting around casting and I only need to regard a couple of types I think all the generics-based solutions are a bit overkill in my case. So I simply added casted getters to my VO ...
public class InputVO
{
public bool isEnabled;
public bool isValid;
public InputType type;
public object value;
public int IntValue { get { return (int)value; } }
public float FloatValue { get { return (float)value; } }
public bool BoolValue { get { return (bool)value; } }
public Vector2 Vector2Value { get { return (Vector2) value; } }
public Vector3 Vector3Value { get { return (Vector3)value; } }
}

Implicit casting using Generic Helper class

Why do I get a type conversion compile error for the following piece of code?
I have quite a few instances of derived Def/View classes in my project. All of them have some code base, say persistence, retrieval etc. I thought by writing a helper class using generics I could achieve maintainability of this common code base.
However I get 'Type Conversion' compilation error in the DoSomeStuff method on the line that assigns the view to def. I have taken care to write implicit cast conversion for all of base and derived classes.
Note that Def & View classes intentionally do not derive from some common class. Additionally I always want to convert only from View to Def and never the other way round, hence only my View classes have the implicit conversion defined on them.
I did try to follow Eric Lipert's discussion on Covariance and Contravariance, but got quite muddled up in my head as he progressed with his examples. Any help with this problem is greatly appreciated.
public class BaseDef
{
public int Id { get; set; }
}
public class DerivedDef : BaseDef
{
public string Name { get; set; }
public DerivedDef()
: base()
{
}
public DerivedDef(BaseDef bd)
{
this.Id = bd.Id;
}
}
public class BaseView
{
public int Id { get; set; }
public BaseView()
{
}
public BaseView(BaseDef bd)
{
Id = bd.Id;
}
public BaseDef ToBaseDef()
{
return new BaseDef { Id = this.Id };
}
public static implicit operator BaseView(BaseDef bd)
{
return new BaseView(bd);
}
public static implicit operator BaseDef(BaseView bv)
{
return bv.ToBaseDef();
}
}
public class DerivedView : BaseView
{
public string Name { get; set; }
public DerivedView()
: base()
{
}
public DerivedView(DerivedDef dd)
: base(dd)
{
Name = this.Name;
}
public DerivedDef ToDerivedDef()
{
return new DerivedDef(this)
{
Name = this.Name,
};
}
}
public class SomeHelper<Tdef, Tview>
where Tdef : BaseDef
where Tview : BaseView
{
public void DoSomeStuff(Tview vm)
{
Tdef df = vm; // this line give a compile error 'Cannot convert type 'Tview' to 'Tdef'
// work with df from here on
}
}
There's no guarantee that there is a conversion to Tdef. There's definitely a conversion to BaseDef, and the compiler will use that conversion:
BaseDef df = vm; // This is fine
... but that's not the same thing.
In this case, that conversion is actually going to return a BaseDef anyway - there is no conversion operator from DerivedView to DerivedDef... there's a method (ToDerivedDef) but there's nothing in your code which would call it. Even if the conversion existed in this particular case, the compiler can't guarantee that it exists.
You could use:
Tdef df = (Tdef) (BaseDef) vm;
... that would perform the user-defined conversion to BaseDef, and then a normal cast to Tdef - which would fail at execution time in your case, but could work if the conversion called an appropriate virtual method. It can't be guaranteed at compile-time though.
I really couldn't use Jon's approach as I had layering constraints. The def model(s) are defined in the DB layer while the view model(s) in the UI layer.
However, drawing inspiration from Jon's comment, how I solved the issue at hand was to add implicit conversion on all the view model(s) and exposed two properties on the helper class that handled the conversion to & fro. This is how the final code looks...
public class BaseDef
{
public int Id { get; set; }
public override string ToString()
{
return Id.ToString();
}
}
public class BaseView
{
public int Id { get; set; }
public BaseView()
{
}
public BaseView(BaseDef bd)
{
Id = bd.Id;
}
public BaseDef ToBaseDef()
{
return new BaseDef { Id = this.Id };
}
public static implicit operator BaseView(BaseDef bd)
{
return new BaseView(bd);
}
public static implicit operator BaseDef(BaseView bv)
{
return bv.ToBaseDef();
}
}
public class DerivedDef : BaseDef
{
public string Name { get; set; }
public DerivedDef()
: base()
{
}
public DerivedDef(BaseDef bd)
{
this.Id = bd.Id;
}
}
public class DerivedView : BaseView
{
public string Name { get; set; }
public DerivedView()
: base()
{
}
public DerivedView(DerivedDef dd)
: base(dd)
{
Name = this.Name;
}
public DerivedDef ToDerivedDef()
{
return new DerivedDef((BaseView)this)
{
Name = this.Name,
};
}
public static implicit operator DerivedView(DerivedDef dd)
{
return new DerivedView(dd);
}
public static implicit operator DerivedDef(DerivedView dv)
{
return dv.ToDerivedDef();
}
}
public class SomeHelper<Tdef, Tview>
where Tdef : BaseDef
where Tview : BaseView
{
public Func<Tview, Tdef> ConvertToDef { get; set; }
public Func<Tdef, Tview> ConvertToView { get; set; }
public Tdef Convert(Tview vm)
{
if (ConvertToDef == null)
{
throw new ArgumentNullException("ConvertToDef uninitialized");
}
return ConvertToDef(vm);
}
public Tview Convert(Tdef dm)
{
if (ConvertToView == null)
{
throw new ArgumentNullException("ConvertToView uninitialized");
}
return ConvertToView(dm);
}
}
The consuming code looks like this...
private static void TestCastWithGenerics()
{
BaseDef bd = new BaseDef()
{
Id = 1
};
DerivedView dv = new DerivedView()
{
Id = 1,
Name = "DV",
};
var aClassD = new SomeHelper<DerivedDef, DerivedView>();
aClassD.ConvertToDef = dv1 => dv1; // Behind scenes the implicit cast is being invoked...
DerivedDef dd = aClassD.Convert(dv);
var aClassB = new SomeHelper<BaseDef, BaseView>();
aClassB.ConvertToView = bd1 => bd1; // Behind scenes the implicit cast is being invoked...
BaseView bv = aClassB.Convert(bd);
Console.WriteLine(dd);
Console.WriteLine(bv);
}

EF 4.1 using custom type handling money

I have been using a custom type for Money with my POCOs and tries to insert this to my database but it is implicitly thrown away by Entity Framework.
This is my code made simple;
My type;
public struct Money
{
private static decimal _value;
public Money(Decimal value)
{
_value = value;
}
public static implicit operator Money(Decimal value)
{
return new Money(value);
}
public static implicit operator decimal(Money value)
{
return _value;
}
}
My object;
public class MyObject
{
[Key]
public int Id { get; set; }
public Money MyMoney { get; set; }
}
My context;
public class Data : DbContext
{
public Data()
: base("Data Source=.;Database=MyTest;Integrated Security=True")
{}
public DbSet<MyObject> MyObject { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyObject>()
.Property(p => p.MyMoney).HasColumnName("MyMoney");
}
}
When I use this code I get the following error.
The property 'MyMoney' is not a
declared property on type 'MyObject'.
Verify that the property has not been
explicitly excluded from the model by
using the Ignore method or
NotMappedAttribute data annotation.
Make sure that it is a valid primitive
property.
I guess the problem is the last sentence.... Then, what is a valid primitive property? Is there any other way to take care of this?
You could take of it by explicitly mapping a decimal property and only exposing the Money Property to callers:
public class MyObject
{
[Key]
public int Id { get; set; }
protected decimal MyMoney { get; set; }
public Money MyMoneyStruct
{
get { return (Money)this.MyMoney; }
set { this.MyMoney = (decimal)value; }
}
}
Ok, this went to be my solution.
public class MyObject
{
[Key]
public int Id { get; set; }
public Money MyMoney { get { return (Money)MyMoneyInternal; } set { MyMoneyInternal = (decimal)value; } }
private decimal MyMoneyInternal { get; set; }
}
To be able to read that private property I created a property extension as below. Since some of my properties of type Money is Nullable I had to take care of that as well.
public static class PropertyExtensions
{
public static PrimitivePropertyConfiguration Property<TClass, TProperty>(this EntityTypeConfiguration<TClass> etc, string propertyName)
where TClass : class
where TProperty : struct
{
PrimitivePropertyConfiguration returnValue;
Type type = typeof(TClass);
var propertyInfo = type.GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
ParameterExpression parameterExpression = Expression.Parameter(type, "xyz");
MemberExpression memberExpression = Expression.Property((Expression)parameterExpression, propertyInfo);
if (IsNullable(memberExpression.Type))
{
returnValue = etc.Property((Expression<Func<TClass, TProperty?>>)Expression.Lambda(memberExpression, parameterExpression));
}
else
{
returnValue = etc.Property((Expression<Func<TClass, TProperty>>)Expression.Lambda(memberExpression, parameterExpression));
}
return returnValue;
}
private static bool IsNullable(Type type)
{
bool result;
if (type.IsGenericType)
{
var genericType = type.GetGenericTypeDefinition();
result = genericType.Equals(typeof(Nullable<>));
}
else
{
result = false;
}
return result;
}
}
And then I could use that to read my private property.
modelBuilder.Entity<MyObject>()
.Property<MyObject, decimal>("MyMoneyInternal").HasColumnName("MyMoney");
Thank you Steve for taking me in the right direction.
You could also have transformed your "Money" in a Complex class; which would make the exposed properties in-line in your database. With only the Decimal property, it would look like Money_Value (given you expose Value as a property). Let's say you add "Currency" as a string to the class. You would then have also Money_Currency in the database.
To declare to EF that your class is a Complex type, just annotate it with [ComplexType()].
To get the best of Struct + ComplexType, you could even use both at the time : the complex type using the struct internally (the ComplexType just being a wrapper).

Categories

Resources