My current code is following, it is a WCF service method exposed as a proxy to the client:
public UnifiedDTO GetAllCardTitle(string trainSymbolOrCarLocation,
DateTime startDate,
DateTime endDate,
string procedureName = CardTitle.procedureNameTrainRuns)
This method takes a procedure name (as the last parameter) and rest of the parameters are the binding the input parameters, however the issue is that we do not have the flexibility in the case of parameters numbers and types changing. The project is in its initial stage, so changes will surely be made.
The options that I have is convert the method as follows:
public UnifiedDTO GetAllCardTitle(params object [] parameters)
Where we have the freedom to pass the parameters and procedure details and can accordingly bind. However, there might be a performance issue due to boxing and unboxing. It would require client application to pass the parameters with correct order and value to bind as it would be expected by underlying layers
public UnifiedDTO GetAllCardTitle(List<Filter> parameter, string procedureName)
Where Parameter class would be defined as:
public class Filter
{
public string name { set; get; }
public string value { set; get; }
public string dataTypeID { set; get; }
public Filter(string _name, string _value, string _dataTypeID)
{
name = _name;
value = _value;
dataTypeID = _dataTypeID;
}
}
In this method for a given procedure, we bind each parameter with its name value and DataType, and it would need value to typecasted to the correct data type, it has more flexibility then last method and can be passed in any order, as binding is by name. However, it would need much more due diligence from the application.
Is there still a better way to take care of this situation using something new introduced in C#.Net?
None. Use Dynamic object instead
To create a C# class that works with the DLR, the easiest thing to do is derive from DynamicObject. One limitation arises when trying to use a dynamic type in a WCF service. Trying to use a DynamicObject-derived type will result in a runtime exception when trying to serialize with WCF’s DataContractSerializer.
[DataContract]
public class SerializableDynamicObject : IDynamicMetaObjectProvider
{
[DataMember]
private IDictionary<string,object> dynamicProperties = new Dictionary<string,object>();
#region IDynamicMetaObjectProvider implementation
public DynamicMetaObject GetMetaObject (Expression expression)
{
return new SerializableDynamicMetaObject(expression,
BindingRestrictions.GetInstanceRestriction(expression, this), this);
}
#endregion
#region Helper methods for dynamic meta object support
internal object setValue(string name, object value)
{
dynamicProperties.Add(name, value);
return value;
}
internal object getValue(string name)
{
object value;
if(!dynamicProperties.TryGetValue(name, out value)) {
value = null;
}
return value;
}
internal IEnumerable<string> getDynamicMemberNames()
{
return dynamicProperties.Keys;
}
#endregion
}
public class SerializableDynamicMetaObject : DynamicMetaObject
{
Type objType;
public SerializableDynamicMetaObject(Expression expression, BindingRestrictions restrictions, object value)
: base(expression, restrictions, value)
{
objType = value.GetType();
}
public override DynamicMetaObject BindGetMember (GetMemberBinder binder)
{
var self = this.Expression;
var dynObj = (SerializableDynamicObject)this.Value;
var keyExpr = Expression.Constant(binder.Name);
var getMethod = objType.GetMethod("getValue", BindingFlags.NonPublic | BindingFlags.Instance);
var target = Expression.Call(Expression.Convert(self, objType),
getMethod,
keyExpr);
return new DynamicMetaObject(target,
BindingRestrictions.GetTypeRestriction(self, objType));
}
public override DynamicMetaObject BindSetMember (SetMemberBinder binder, DynamicMetaObject value)
{
var self = this.Expression;
var keyExpr = Expression.Constant(binder.Name);
var valueExpr = Expression.Convert(value.Expression, typeof(object));
var setMethod = objType.GetMethod("setValue", BindingFlags.NonPublic | BindingFlags.Instance);
var target = Expression.Call(Expression.Convert(self, objType),
setMethod,
keyExpr,
valueExpr);
return new DynamicMetaObject(target,
BindingRestrictions.GetTypeRestriction(self, objType));
}
public override IEnumerable<string> GetDynamicMemberNames ()
{
var dynObj = (SerializableDynamicObject)this.Value;
return dynObj.getDynamicMemberNames();
}
}
One warning, dynamic members can be anything, meaning at runtime someone could assign a method to one of these fields. If this is possible in your application, you’ll need to ensure any methods assigned to the dynamic type are not serialized. I’m leaving this as an exercise for the reader.
Taken from Here
Is it possible to allow an "Interfaced" parameter. From that, you could handle multiple things based on the interfaced value setting. Just shooting out a simple sample.
public enum eWhatAmI
{
ListedObjects,
StringArrays,
Other
}
public interface IWhatParmType
{
eWhatAmI whatAmI { get; set; }
}
public class MyListVersion : IWhatParmType
{
public eWhatAmI whatAmI { get; set; }
public List<string> whatever { get; set; }
public MyListVersion()
{
whatAmI = eWhatAmI.ListedObjects;
whatever = new List<string>();
... build out list of strings
}
}
public class MyArrayVersion : IWhatParmType
{
public eWhatAmI whatAmI { get; set; }
public string[] whatever { get; set; }
public MyArrayVersion()
{
whatAmI = eWhatAmI.StringArrays;
... build out array of strings
}
}
etc...
Then in your process for handling whatever the incoming parameter is, you can handle either way.
public UnifiedDTO GetAllCardTitle(IWhatParmType parameter, string procedureName)
{
switch( parameter )
{
case (eWhatAmI.ListedObjects):
// Just for grins, test to make sure object really IS expected list version object
if( parameter is MyListVersion)
DoViaList( (MyListVersion)parameter );
break;
case (eWhatAmI.StringArrays ):
if( parameter is MyArrayVersion )
DoViaArray( (MyArrayVersion)parameter );
break;
}
}
private void DoViaList( MyListVersion parm1 )
{
.. do whatever based on the "List<string>" property
}
private void DoViaArray( MyArrayVersion parm1 )
{
.. do whatever based on the "string []" property
}
Then, if you ever needed to expand a setting per a particular object instance, you could and handle within the specific sub-handler method for populating or forcing whatever defaults to be implied.
Related
This is probably a stupid question, but just in case....
We have a 3rd party package with weird models like:
public partial class CountingDevice
{
public int countingDeviceNo { get; set; }
public string countingDeviceName { get; set; }
public string obis { get; set; }
public int integralPart { get; set; }
public bool integralPartFieldSpecified;
public int fractionalPart { get; set; }
public bool fractionalPartFieldSpecified;
public double value { get; set; }
public bool valueFieldSpecified;
public bool offPeakFlag { get; set; }
public bool offPeakFlagFieldSpecified;
public ExpectedMeterReading expectedMeterReading { get; set; }
// snipped for brevity
}
You'll notice that sometimes there are pairs of fields like integralPart and integralPartFieldSpecified.
Here is the problem: If I simply assign some value to integralPart but do not set integralPartFieldSpecified = true, the value of integralPart will be completely ignored causing the solution to fail.
So when mapping our own models to this madness, I need to litter the code with constructs like:
if (IntegralPart != null)
{
countingDevice.integralPartSpecified = true;
countingDevice.integralPart = (int)IntegralPart!;
}
Both in the interest of reducing lines of code and not stumbling over a minefield, I would like to do any one of the following:
A. Overload the = operator so it will automatically check for a property which is a boolean and has "Specified" concatenated to the current property's name. If such a property exists, it will be assigned true when the value is assigned; if not, then assignment will operate as normal. Ideally, it should be "smart" enough to assign "...Specified" to false if the value assigned is null/default/empty.
B. Create some customer operator which will do the same as A.
C. Create some method which I could invoke in a concise and preferably typesafe way to do the same.
Is this possible?
If so, how?
To make it clear: I need to build quite a few wrappers.
I don't want to repeat this logic for every field and worry about missing some fields which it applies to.
I want a generic way of assigning both fields at once if the "Specified" field exists and being able to do assignments in exactly the same way if it does not exist.
not stumbling over a minefield
Encapsulate the minefield.
If you don't control this 3rd party DTO then don't use it throughout your domain. Encapsulate or wrap the integration of this 3rd party tool within a black box that you control. Then throughout your domain use your models.
Within the integration component for this 3rd party system, simply map to/from your Domain Models and this 3rd party DTO. So this one extra line of code which sets a second field on the DTO only exists in that one place.
Another (expensive) solution would be to write a method that takes in an object, a property name, and the new property value. You can then use reflection to both set the property value for the specified property, as well as search for the bool field that you want to set (if it exists).
Note that you need to pass the correct type for the property. There's no compile-time checking that you're passing a double instead of a string for the value property, for example.
Below I've created an extension method on the object type to simplify calling the method in our main code (the method becomes a member of the object itself):
public static class Extensions
{
// Requires: using System.Reflection;
public static bool SetPropertyAndSpecified(this object obj,
string propertyName, object propertyValue)
{
// Argument validation left to user
// Check if 'obj' has specified 'propertyName'
// and set 'propertyValue' if it does
PropertyInfo prop = obj.GetType().GetProperty(propertyName,
BindingFlags.Public | BindingFlags.Instance);
if (prop != null && prop.CanWrite)
{
prop.SetValue(obj, propertyValue, null);
// Check for related "FieldSpecified" field
// and set it to 'true' if it exists
obj.GetType().GetField($"{propertyName}FieldSpecified",
BindingFlags.Public | BindingFlags.Instance)?.SetValue(obj, true);
return true;
}
return false;
}
}
After you add this class to your project, you can do something like:
static void Main(string[] args)
{
var counter = new CountingDevice();
// Note that 'valueFieldSpecified' and `integralPartFieldSpecified'
// are set to 'false' on 'counter'
// Call our method to set some properties
counter.SetPropertyAndSpecified(nameof(counter.integralPart), 42);
counter.SetPropertyAndSpecified(nameof(counter.value), 69d);
// Now 'valueFieldSpecified' and 'integralPartFieldSpecified'
// are set to 'true' on 'counter'
}
You cannot overload the = operator in C#.
You can just use custom properties and set the "FieldSpecified" fields in the setters e.g.
private int _integralPart;
public int integralPart
{
get { return _integralPart; }
set
{
_integralPart = value;
integralPartFieldSpecified = true;
}
}
public bool integralPartFieldSpecified;
Update
If you want a generic solution you can use a generic class for properties that you want to achieve the specified behaviour with e.g.
public class ValueWithSpecifiedCheck<T>
{
private T _fieldValue;
public T FieldValue
{
get
{
return _fieldValue;
}
set
{
_fieldValue = value;
FieldSpecified = true;
}
}
public bool FieldSpecified { get; set; }
}
public class Data
{
public ValueWithSpecifiedCheck<int> IntegralPart { get; set; }
}
Then the class/property would be used as following:
public static void Main()
{
var data = new Data();
data.IntegralPart = new ValueWithSpecifiedCheck<int>();
data.IntegralPart.FieldValue = 7;
Console.WriteLine(data.IntegralPart.FieldSpecified);// Prints true
}
If you implement a generic solution and add implicit conversion operators, it's quite convenient to use.
Here's a sample Optional<T> struct (I made it a readonly struct to ensure immutable mechanics):
public readonly struct Optional<T> where T : struct
{
public Optional(T value)
{
_value = value;
}
public static implicit operator T(Optional<T> opt) => opt.Value;
public static implicit operator Optional<T>(T opt) => new(opt);
public T Value => _value!.Value;
public bool Specified => _value is not null;
public override string ToString() => _value is null ? "<NONE>" : _value.ToString()!;
readonly T? _value;
}
You could use that to implement your CountingDevice class like so:
public partial class CountingDevice
{
public int countingDeviceNo { get; set; }
public string countingDeviceName { get; set; }
public string obis { get; set; }
public Optional<int> integralPart { get; set; }
public Optional<int> fractionalPart { get; set; }
public Optional<double> value { get; set; }
public Optional<bool> offPeakFlag { get; set; }
// snipped for brevity
}
Usage is quite natural because of the implicit conversions:
public static void Main()
{
var dev = new CountingDevice
{
integralPart = 10, // Can initialise with the underlying type.
value = 123.456
};
Console.WriteLine(dev.fractionalPart.Specified); // False
Console.WriteLine(dev.integralPart.Specified); // True
Console.WriteLine(dev.value); // 123.456
Console.WriteLine(dev.value.ToString()); // 123.456
Console.WriteLine(dev.fractionalPart.ToString()); // "<NONE>"
dev.fractionalPart = 42; // Can set the value using int.
Console.WriteLine(dev.fractionalPart.Specified); // True
Console.WriteLine(dev.fractionalPart); // 42
var optCopy = dev.offPeakFlag;
Console.WriteLine(optCopy.Specified); // False
dev.offPeakFlag = true;
Console.WriteLine(dev.offPeakFlag.Specified); // True
Console.WriteLine(optCopy.Specified); // Still False - not affected by the original.
Console.WriteLine(optCopy); // Throws an exception because its not specified.
}
You might also want to use optional reference types, but to do that you will need to declare a generic with the class constraint:
public readonly struct OptionalRef<T> where T : class
{
public OptionalRef(T value)
{
_value = value;
}
public static implicit operator T(OptionalRef<T> opt) => opt.Value;
public static implicit operator OptionalRef<T>(T opt) => new(opt);
public T Value => _value ?? throw new InvalidOperationException("Accessing an unspecified value.");
public bool Specified => _value is not null;
public override string ToString() => _value is null ? "<NONE>" : _value.ToString()!;
readonly T? _value;
}
Personally, I think that's a bit overkill. I'd just use nullable value types, int?, double? etc, but it depends on the expected usage.
C# doesn't allow overloading the = operator (unlike eg C++). However, your suggestion C should work. It's a bit of a hassle, too, since you'll have to write a bunch of methods, but you could write an extension method such as
public static class Extensions
{
public static void UpdateIntegralPart(this CountingDevice dev, double value)
{
dev.integralPart = value;
dev.integralPartSpecified = true;
}
}
Then you can call
countingDevice.UpdateIntegralPart(1234);
Just to clarify, I have this working using dynamic and MakeGenericType. But I cant help but think there is a better way to do this. What I am trying to do is create a "plug-in" loader, using Unity. I will just explain it as I post the code so you can get a sense for what I am doing.
First I'll just post the plug-in itself:
[RegisterAction("MyPlugin", typeof(bool), typeof(MyPlugin))]
public class MyPlugin: IStrategy<bool>
{
public IStrategyResult<bool> Execute(ISerializable info = null)
{
bool result;
try
{
// do stuff
result = true;
}
catch (Exception)
{
result = false;
}
return new StrategyResult<bool>
{
Value = result
};
}
}
Couple things to note here. First is the RegisterActionAttribute:
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public StrategyAction StrategyAction { get; }
public RegisterActionAttribute(string actionName, Type targetType, Type returnType, params string[] depdencies)
{
StrategyAction = new StrategyAction
{
Name = actionName,
StrategyType = targetType,
ResponseType = returnType,
Dependencies = depdencies
};
}
}
Then the interfaces:
public interface IStrategy<T>
{
IStrategyResult<T> Execute(ISerializable info = null);
}
public interface IStrategyResult<T>
{
bool IsValid { get; set; }
T Value { get; set; }
}
All fairly straight forward. The goal here is just to attach some meta-data to the class when it is loaded. The loading happens via unity using a wrapper that simply loads the assemblies in the bin directory using a file search pattern and adds it to a singleton class with a collection of StrategyActions. I don't need paste all the unity code here as I know it works and registers and resolves the assemblies.
So now to the meat of the question. I have a function on the singleton that executes actions. These are applied with Unity.Interception HandlerAttributes and passed a string like so (I can post the code for this but I didn't think it was relevant):
[ExecuteAction("MyPlugin")]
The handler calls the following execute function on the singleton class to "execute" functions that are registered (added to the collection).
public dynamic Execute(string action, params object[] parameters)
{
var strategyAction = _registeredActions.FirstOrDefault(a => a.Name == action);
if (strategyAction == null)
return null;
var type = typeof (IStrategy<>);
var generic = type.MakeGenericType(strategyAction.StrategyType);
var returnType = typeof (IStrategyResult<>);
var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = UnityManager.Container.Resolve(generic, strategyAction.Name);
var method = instance.GetType().GetMethod("Execute");
return method.Invoke(instance, parameters);
}
This execute is wrapped in an enumerator call which returns a collection of results, which sorts to manage dependencies and what not (see below). These values are referenced by the caller using the Value property of ISTrategyResult{T} to do various things defined by other business rules.
public List<dynamic> ExecuteQueuedActions()
{
var results = new List<dynamic>();
var actions = _queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
_queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
Now mind you, this works, and I get the return type that is specified by the plugins RegisterAction attribute. As you can see I am capturing the Type of the plugin and the return type. I am using the "generic" variable to resolve the type with unity through the use of MakeGenericType, which works fine. I am also creating a generic representing the return type based on the type from the collection.
What I don't like here is having to use dynamic to return this value to a function. I can't figure out a way to return this as a IStrategyResult{T} because obviously the caller to "dynamic Execute(..." can not, at run-time, imply return type of the function. I mulled around with making the call to Execute with a MakeGenericMethod call as I actually have the expected type the StrategyAction. It would be cool if I could some how figure out away to return a strongly typed result of IStrategyResult{T} while determining the type of T during the call.
I do understand why I cannot do this with my current implementation I am just trying to find a way to wrap all this functionality without using dynamic. And was hoping somebody could provide some advice that might be useful. If that means wrapping this with other calls to non-generic classes or something like that, that would be fine as well if that is the only solution.
You need a more sweeping refactor than just figure out how to call your plugin.
There's no need for the [RegisterAction] attribute to hold targetType and returnType, these parameters to the attribute can easily get out of sync with code, making them a potential hole to fall into.
Then think from the other side of your setup: how do you consume the data, what do you do with your IStrategyResult<> - does it really have to be generic or there is a specific way you could encapsulate the type of results? I can't quite imagine a plugin system that returns "anything" to the host. The hint is really in your dynamic Execute(...) - your parameters and your result have both lost their strong typing, showing you that strong-typing the plugin is not helping with anything. Just use object or - better - make a StrategyResult class instead of the current interface and provide whatever properties are necessary there (I've added a few frivolous examples), such as:
public class StrategyResult{
public object Result{get;set;}
public Type ResultType {get;set;}
// frivolous examples
public bool IsError {get;set;}
public string ErrorMessage {get;set;}
// really off-the-wall example
public Func<StrategyHostContext,bool> ApplyResultToContext {get;set;}
public StrategyResult(){
}
public StrategyResult FromStrategy(IStrategy strategy){
return new StrategyResult{
ResultType = strategy.ResultType
}
}
public StrategyResult FromStrategyExecute(IStrategy strategy, ISerializable info = null){
var result = FromStrategy(strategy);
try{
strategy.Execute(info);
} catch (Exception x){
result.IsError = true;
result.ErrorMessage = x.Message;
}
}
}
Then your IStrategy becomes:
public interface IStrategy{
Type ResultType {get;}
void Initialize(SomeContextClassMaybe context);
StrategyResult Execute(ISerializable info = null);
}
You can also change your attribute to make it more efficient to load large plugins:
[AttributeUsage(AttributeTargets.Assembly)]
public sealed class AddinStrategyAttribute : Attribute
{
public Type StategyType {get; private set;}
public AddinStrategyAttribute(Type strategyType){
StrategyType = strategyType;
}
}
... and use the attribute like so:
[assembly:AddinStrategy(typeof(BoolStrategy))] // note it's outside the namespace
namespace MyNamespace{
public class BoolStrategy: IStrategy{
public Type ResultType { get{ return typeof(bool);}}
public void Initialize (SomeContextClassMaybe context){
}
public StrategyResult Execute(ISerializable info = null){
return StrategyResult.FromStrategyExecute(this,info);
}
}
}
Assuming that the caller of ExecuteActions does not have any knowledge about the T in any of the plugins or results and must work with dynamic or object anyway, then the following may work:
Infrastructure:
public interface IStrategy
{
IStrategyResult Execute(ISerializable info = null);
}
public interface IStrategyResult
{
bool IsValid { get; }
dynamic Value { get; }
}
public class StrategyResult<T> : IStrategyResult
{
public T Value { get; private set; }
public StrategyResult(T value) { this.Value = value; }
public bool IsValid { get { throw new NotImplementedException(); } }
dynamic IStrategyResult.Value { get { return this.Value; } }
}
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public List<string> Dependencies { get; private set; }
public RegisterActionAttribute(params string[] depdencies)
{
this.Dependencies = new List<string>(depdencies);
}
}
public class StrategyAction
{
public string Name;
public List<string> Dependencies;
}
public abstract class BasePlugin<T> : IStrategy
{
public IStrategyResult Execute(ISerializable info = null)
{
return new StrategyResult<T>(this.execute(info));
}
protected abstract T execute(ISerializable info);
}
Example plugin:
[RegisterAction]
public class MyFirstPlugin: BasePlugin<bool>
{
protected override bool execute(ISerializable info = null)
{
try
{
// do stuff
return true;
}
catch (Exception)
{
return false;
}
}
}
[RegisterAction("MyFirstPlugin")]
public class MySecondPlugin: BasePlugin<string>
{
protected override string execute(ISerializable info = null)
{
try
{
// do stuff
return "success";
}
catch (Exception)
{
return "failed";
}
}
}
Example execution engine:
public class Engine
{
public List<StrategyAction> registeredActions = new List<StrategyAction>();
private List<StrategyAction> queuedActions = new List<StrategyAction>();
public IStrategyResult Execute(string action, ISerializable info = null)
{
if (this.registeredActions.FirstOrDefault(a=>a.Name == action) == null) return null;
// This code did not appear to be used anyway
//var returnType = typeof (IStrategyResult<>); //var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = (IStrategy) UnityManager.Container.Resolve(typeof(IStrategy), action);
return instance.Execute(info);
}
public List<IStrategyResult> ExecuteQueuedActions()
{
var results = new List<IStrategyResult>();
var actions = this.queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
this.queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
}
Note that when the plugins are loaded, the RegisterActionAttribute information along with the name of the plugin type loaded need to be combined into a StrategyAction instance and loaded into the registeredActions field of the engine.
The above allows the plugins to work with strong types but still allows the engine to deal with a variety of types. If you need the engine to work with more strongly typed data, then please provide an example of how the callers of ExecuteQueuedActions are expected to work with the results from ExecuteQueuedActions.
You got into this pickle by giving your RegisterActionAttribute constructor the returnType argument. Since you have only one Execute() method, you are forced to deal with the fact that the return type can be different types.
Using dynamic is about as good as it gets. You can make Execute() generic but then you'll have to deal with a mismatch between its type parameter and the attribute's ResponseType. Not one that the compiler can catch, this fails at runtime. It isn't generic.
Frankly, this strongly sounds like one flexibility too many. At the risk of interpreting the point of having a return type incorrectly, the outcome of a "registration action" is rather boolean. It worked or it didn't work. And is in fact the way you implemented it, your first plugin snippet does return bool.
With very high odds that you should not use bool either. Failure ought to make a bang, you'd throw an exception.
Why not define a super interface IStrategyResult like this:
interface IStrategyResult
{
Type ReturnType { get; }
}
interface IStrategyResult<T> : IStrategyResult
{
// your code here
}
Then define your execute like this:
public IStrategyResult Execute(string action, params object[] parameters)
And have your StrategyResult : IStrategyResult<T> class set the property to return typeof(T)
By convention you could assume (or enforce using inheritance on an abstract StrategyResult<T> : IStrategyResult<T> class) the T to be the same as the ReturnType property of the non-generic IStrategyResult interface.
Short Question:
Provided I have given an implicit conversion mechanism for my object to convert its values from a plain string, can it be made to auto-bind to ViewModel's property?
Details:
I have a complex object like so (simplified for brevity and clarity)
public enum PrimaryScopeEnum {
Pivot1,
Pivot2
}
public enum SecondaryScopeEnum {
Entity1,
Entity2,
Entity3,
Entity4
}
public class DataScope {
public PrimaryScopeEnum PrimaryScope { get; set; }
public SecondaryScopeEnum SecondaryScope { get; set; }
public static implicit operator DataScope ( string combinedScope ) {
DataScope ds = new DataScope();
// Logic for populating Primary and Secondary Scope enums
return ds;
}
}
I am using the above object in my view model as below:
public enum PageModeEnum {
View,
Add,
Edit
}
public class DisplayInfoViewModel {
public string SetID { get; set; }
public PageModeEnum PageMode { get; set; }
public DataScope Scope { get; set; }
}
And the Action in my Controller is set as
// Accessed with /MyController/DisplayInfo?SetID=22&PageMode=View&Scope=Pivot1
public virtual ActionResult DisplayInfo ( DisplayInfoViewModel vm ) {
// vm.SetID is 22
// vm.PageMode is PageModeEnum.View
// vm.Scope is null
return View ( vm );
}
My issue is in the Action, even though I have given an implicit casting from string to DataScope class it fails to properly bind during execution.
I have tested the casting with the value that is being passed (Pivot1 here) separately and the casting works fine.
Is there a way to make this casting happen implicitly or should I change the view models Scope variable to plain string and then do a manual casting.
No, the default model binder doesn't use any implicit operators. You will have to write a custom model binder for the DataScope type and manually bind it from the request string if you want that to work.
For example:
public class DataScopeModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (value == null)
{
return null;
}
return (DataScope)value.RawValue;
}
}
which you are then going to associate with the DataScope type in your Application_Start:
ModelBinders.Binders.Add(typeof(DataScope), new DataScopeModelBinder());
I am trying to figure out something with c# code, and I'm not 100% sure if it is possible, but I am trying to implement search functionality for several classes which is streamlined and overall easy to develop for. Right now I have the following code:
[DataContract(IsReference = true), Serializable]
public class ClassSearch
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
public override string ToString()
{
return String.Format("{0} = {1}", Name, Value);
}
... // additional logic
}
However, I would like to include strong typing for the object value so that it only can be set to the property that is passed in, I guess like similar (hypothetical, not sure if this would work)
[DataContract(IsReference = true), Serializable]
public class ClassSearch<TProperty>
{
[DataMember]
public TProperty Property {get; set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
... // additional logic
}
public class MainClass
{
public void Execute()
{
SomeClass someClass = new Class{
Property = "Value";
};
ClassSearch search = new ClassSearch<SomeClass.Property>{
Property = someClass.Property
};
var retString = search.ToString(); // Returns "Property = 'Value'"
}
}
It seems you are trying to create a WCF service to be able to pass any type you like.
First of all, this is not WSDL-friendly. All WCF services needs to be able to be exposed in WSDL. WSDL is all about well-defined contracts hence the types need be all defined. So that generic approach would not work - mainly because of WSDL. Having said that, you still can use generics but then you have to use KnownType and actually define all the types possible - which for me defeats the object.
Yet, one thing you can do is to serialize the object yourself and pass around with its type name across the wire. On the other side, you can pick it up deserialize.
So something along the line of:
// NOTE: Not meant for production!
[DataContract]
public class GenericWcfPayload
{
[DataMember]
public byte[] Payload {get; set;}
[DataMember]
public string TypeName {get; set;}
}
If there are no easier answers I would try it with this one.
You could use expressions like so:
// Sample object with a property.
SomeClass someClass = new SomeClass{Property = "Value"};
// Create the member expression.
Expression<Func<object /*prop owner object*/, object/*prop value*/>> e =
owner => ((SomeClass)owner).Property;
// Get property name by analyzing expression.
string propName = ((MemberExpression)e.Body).Member.Name;
// Get property value by compiling and running expression.
object propValue = e.Compile().Invoke(someClass);
You hand over your property by the member expression owner => ((SomeClass)owner).Property. This expression contains both information you need: property name and property value. The last two lines show you how to get name and value.
Following a larger example:
class MainClass
{
public static void Execute()
{
SomeClass someClass = new SomeClass{
Property = "Value"
};
var search = new ClassSearch(s => ((SomeClass)s).Property);
Console.Out.WriteLine("{0} = '{1}'", search.Property.Name, search.Property.GetValue(someClass));
}
}
class Reflector
{
public static string GetPropertyName(Expression<Func<object, object>> e)
{
if (e.Body.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("Wrong expression!");
}
MemberExpression me = ((MemberExpression) e.Body);
return me.Member.Name;
}
}
class ClassSearch
{
public ClassSearch(Expression<Func<object, object>> e)
{
Property = new PropertyNameAndValue(e);
}
public PropertyNameAndValue Property { get; private set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
}
class PropertyNameAndValue
{
private readonly Func<object, object> _func;
public PropertyNameAndValue(Expression<Func<object, object>> e)
{
_func = e.Compile();
Name = Reflector.GetPropertyName(e);
}
public object GetValue(object propOwner)
{
return _func.Invoke(propOwner);
}
public string Name { get; private set; }
}
class SomeClass
{
public string Property { get; set; }
}
The main part of that example is the method Reflector.GetPropertyName(...) that returns the name of a property within an expression. I.e. Reflector.GetPropertyName(s => ((SomeClass)s).Property) would return "Property".
The advantage is: This is type-safe because in new ClassSearch(s => s.Property) compiling would end with an error if SomeClass would not have a property 'Property'.
The disadvantage is: This is not type-safe because if you write e.g. new ClassSearch(s => s.Method()) and there would be a method 'Method' then there would be no compile error but a runtime error.
I tried to search for an answer for this problem but could not find much, most probably because I do not know how to look for it properly, so here it goes. All help is very much appreciated.
With the base class that looks like
abstract public class Property
{
private String name;
public Property(String propertyName)
{
name = propertyName;
}
public String Name
{
get { return name; }
}
abstract public override String ToString();
}
And derived classes that look like
public class StringProperty : Property
{
private String value; // different properties for different types
public StringProperty(String propertyName, String value) : base(propertyName)
{
this.value = value;
}
public String Value // different signature for different properties
{
get { return value; }
}
public override String ToString()
{
return base.Name + ": " + value;
}
}
During runtime, the function receives a collection of "Property" objects. What do I need to do to be able to obtain the "Value" of each? Do I need to have a big if statement to query the type of each "Property" object? If not, is there a more elegant solution?
I tried to define an abstract "Value" property to be overridden but since the return types are different, it did not work. I also tried playing with shadowing the "Value" property, but I could not make it work. The idea of using an COM-like Variant does not sound very appropriate, either.
Thanks a lot in advance.
EDIT:
I should have added details as to what I am trying to do. The properties are displayed in a Winforms app. Different "TextBox"es represent different properties and are filtered for proper input (depending on the type). The updated values are read back and stored. The container object will be serialized into JSON and deserialized on an Android and iPhone client and eventually these values will be passed into a layer running native C++ code doing OpenGL stuff. I don't know in advance the kind of all needed properties so as the middleman, I wanted to make my code as robust as possible while being able to feed the OpenGL engine.
You can use a generic class:
public class AnyProperty<T> : Property
{
private T value;
// ... etc
I'd really recommend making the base class an Interface by now:
public interface IProperty
{
public String Name { get; }
}
public class Property<T> : IProperty
{
public Property(String name, T value)
{
Name = name;
Value = value;
}
public String Name { get; private set; }
public T Value { get; private set; }
public override String ToString()
{
return string.Format("{0}: {1}", Name, Value)
}
}
Here is sample usage:
var intProp = new Property<int> ("age", 32);
var strProp = new Property<string> ("name", "Earl");
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);
To make the construction even simpler, you could have a factory method:
public static Property<T> MakeProperty(string name, T value)
{
return new Property<T>(name,value);
}
var intProp = MakeProperty("age", 32);
var strProp = MakeProperty("name", "Earl");
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);
Not necessarily recommended, and a bit OT:
You could make it even funkier with an extension method:
public static Property<T> AsProp<T>(this T value, string name)
{
return new Property<T>(name,value);
}
var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");
You would have to simply use the object type. What are you trying to accomplish? The problem here isn't the structure of your classes, it's the function that receives the collection of Property objects. It's impossible to even cast something to an unknown type, since you don't know what type of variable it needs to be stored in.
So basically, your Property.Value property needs to be of type object. In your method that uses the Property objects, you need to do something with them, and what you're doing will decide how it should be structured. Are you printing values out? Have a *Value class inheriting from an abstract PropertyValue class and override ToString() to return an appropriate string represention.
I made a few changes to your sample code and got this result...
abstract public class Property
{
private readonly String _name;
public Property(String propertyName)
{
_name = propertyName;
}
public String Name
{
get { return _name; }
}
abstract public override String ToString();
}
public class StringProperty : Property
{
private readonly dynamic _value; // different properties for different types
public StringProperty(String propertyName, dynamic value)
: base(propertyName)
{
this._value = value;
}
public dynamic Value // different signature for different properties
{
get { return _value; }
}
public override String ToString()
{
return base.Name + ": " + _value;
}
}
static void Main(string[] args)
{
StringProperty sp = new StringProperty("A double", 3.444);
StringProperty sp2 = new StringProperty("My int", 4343);
StringProperty sp3 = new StringProperty("My directory", new DirectoryInfo("Some directory"));
StringProperty sp4 = new StringProperty("My null", null);
Console.WriteLine(sp);
Console.WriteLine(sp2);
Console.WriteLine(sp3);
Console.WriteLine(sp4);
}
}
Values are properly printed to the console in the expected way.
It would require a bit of a rethink, but have you considered using the dynamic type (introduced in .net4)
Doesn't really solve your problem, but sidespteps it.
Your properties can bascically just be a
Dictionary<String, dynamic>
, the gotcha is they don't get evaluated until runtime, so you get no compiler support for typing.
so given you want
int SomeValue = MyProperties[SomePropertyName] + 10;
So if
MyProperties[SomePropertyName] = 10; // all is good
if its 76.52 or Fred, the addition will throw an exception at the point it executes.
Code is much simpler and cleaner, no extra casting and the amount of scaffolding required is minimal, BUT, you'll need to unit test code that uses the dictionary extensively and religiously.