xUnit test engine's InlineDataAttribute + optional method parameters - c#

Is it possible to make xUnit test work when you don't specify optional parameter values in InlineDataAttribute?
Example:
[Theory]
[InlineData(1, true)] // works
[InlineData(2)] // error
void Test(int num, bool fast=true){}

Yes it is. There are many ways to do it by redefining some original xunit attributes.
The following code is one of them, which would give you some idea.
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class OptionalTheoryAttribute : TheoryAttribute
{
protected override IEnumerable<ITestCommand> EnumerateTestCommands(IMethodInfo method)
{
var result = (List<ITestCommand>)base.EnumerateTestCommands(method);
try
{
return TransferToSupportOptional(result, method);
}
catch (Exception ex)
{
result.Clear();
result.Add(new LambdaTestCommand(method, () =>
{
throw new InvalidOperationException(
String.Format("An exception was thrown while getting data for theory {0}.{1}:\r\n{2}",
method.TypeName, method.Name, ex)
);
}));
}
return result;
}
private static IEnumerable<ITestCommand> TransferToSupportOptional(
IEnumerable<ITestCommand> testCommands, IMethodInfo method)
{
var parameterInfos = method.MethodInfo.GetParameters();
testCommands.OfType<TheoryCommand>().ToList().ForEach(
testCommand => typeof(TheoryCommand)
.GetProperty("Parameters")
.SetValue(testCommand, GetParameterValues(testCommand, parameterInfos)));
return testCommands;
}
private static object[] GetParameterValues(TheoryCommand testCommand, ParameterInfo[] parameterInfos)
{
var specifiedValues = testCommand.Parameters;
var optionalValues = GetOptionalValues(testCommand, parameterInfos);
return specifiedValues.Concat(optionalValues).ToArray();
}
private static IEnumerable<object> GetOptionalValues(TheoryCommand command, ParameterInfo[] parameterInfos)
{
return Enumerable.Range(command.Parameters.Length, parameterInfos.Length - command.Parameters.Length)
.ToList().Select(i =>
{
EnsureIsOptional(parameterInfos[i]);
return Type.Missing;
});
}
private static void EnsureIsOptional(ParameterInfo parameterInfo)
{
if (!parameterInfo.IsOptional)
{
throw new ArgumentException(string.Format(
"The parameter '{0}' should be optional or specified from data attribute.",
parameterInfo));
}
}
}
internal class LambdaTestCommand : TestCommand
{
private readonly Assert.ThrowsDelegate lambda;
public LambdaTestCommand(IMethodInfo method, Assert.ThrowsDelegate lambda)
: base(method, null, 0)
{
this.lambda = lambda;
}
public override bool ShouldCreateInstance
{
get
{
return false;
}
}
public override MethodResult Execute(object testClass)
{
try
{
lambda();
return new PassedResult(testMethod, DisplayName);
}
catch (Exception ex)
{
return new FailedResult(testMethod, ex, DisplayName);
}
}
}
public class OptionalTheoryTest
{
[OptionalTheory]
[InlineData(1)]
[InlineData(1, true)]
public void TestMethod(int num, bool fast = true)
{
// Arrange
// Act
// Assert
Assert.Equal(1, num);
Assert.True(fast);
}
}

Related

Find the name of the invoked method of a Func delegate

I have a simple invoker where, in order to be able to use a cache library , I need to know the name of the invoked method of an object that is a parameter of a Func delegate.
class Program
{
static void Main(string[] args)
{
var proxy = new Proxy();
Invoker.invoke(proxy, p => p.formatSomething("Dumb test"));
}
}
public class Proxy
{
public string formatSomething(string input){
return String.Format("-===={0}====-", input);
}
}
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy,string> online){
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = ??;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
These are some possible (bad) solutions:
Solution 1: Add a string parameter passing the method name (error prone)
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy,string> online, string methodName){
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
Solution 2: using Expression with possible performance issues.
public static class Invoker
{
public static void invoke(Proxy proxy, Expression<Func<Proxy,string>> online){
var methodName = ((MethodCallExpression)online.Body).Method.Name;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online.Compile()(proxy);
}
}
}
Solution 3: using Expression as another parameter (error prone).
public static class Invoker
{
public static void invoke(Proxy proxy,Func<Proxy,string> online, Expression<Func<Proxy,string>> online2){
var methodName = ((MethodCallExpression)online2.Body).Method.Name;
if (IsCached(proxyName, methodName)){
output = GetFromCache(proxyName, methodName);
}else{
output = online(proxy);
}
}
}
Do you know any other better way to inspect and get the methodName the Invoker needs?
NOTE:
I'm not searching a caching mechanism for the online function result because I already have it.
The only problem is that this cache requires the proxy methodName invoked in the Func delegate.
You need an expression to parse the method's call name, but you can introduce some kind of two-level cache: one for the actual method call (which does not expire), and one for the method's call result (which may expire).
I think, your second solution goes into the right direction; just compile the expression only once.
public static class Invoker {
public static void Invoke(Proxy proxy, Expression<Func<Proxy,string>> online) {
var methodName = ((MethodCallExpression)online.Body).Method.Name;
if (IsCached(proxyName, methodName)) {
output = GetFromCache(proxyName, methodName);
} else {
if (IsFuncCached(methodName)) {
func = GetFuncFromCache(methodName);
} else {
func = online.Compile();
// add func to "func cache"...
}
output = func(proxy);
}
}
}
I tried to adapt your code as an example, I hope it makes sense.
I have recently implemented a solution for inspecting IL instructions of a CLR method.
You can use it like this:
using System;
using System.Linq;
using Reflection.IL;
namespace StackOverflow
{
class Program
{
static void Main(string[] args)
{
var proxy = new Proxy();
Invoker.invoke(proxy, p => p.formatSomething("Dumb test"));
}
}
public class Proxy
{
public string formatSomething(string input)
{
return String.Format("-===={0}====-", input);
}
}
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy, string> online)
{
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = online.GetCalledMethods().First().Name;
Console.WriteLine(methodName);
}
}
}
Note that the code is not thoroughly tested nor documented, but I think it should serve your needs. Here it is:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace Reflection.IL
{
public struct ILInstruction
{
public OpCode Code { get; private set; }
public object Operand { get; private set; }
internal ILInstruction(OpCode code, object operand)
: this()
{
this.Code = code;
this.Operand = operand;
}
public int Size
{
get { return this.Code.Size + GetOperandSize(this.Code.OperandType); }
}
public override string ToString()
{
return this.Operand == null ? this.Code.ToString() : string.Format(CultureInfo.InvariantCulture, "{0} {1}", this.Code, this.Operand);
}
private static int GetOperandSize(OperandType operandType)
{
switch (operandType)
{
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineMethod:
case OperandType.InlineSig:
case OperandType.InlineString:
case OperandType.InlineSwitch:
case OperandType.InlineTok:
case OperandType.InlineType:
return sizeof(int);
case OperandType.InlineI8:
return sizeof(long);
case OperandType.InlineNone:
return 0;
case OperandType.InlineR:
return sizeof(double);
case OperandType.InlineVar:
return sizeof(short);
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
return sizeof(byte);
case OperandType.ShortInlineR:
return sizeof(float);
default:
throw new InvalidOperationException();
}
}
}
public sealed class MethodBodyIL : IEnumerable<ILInstruction>
{
private readonly MethodBase method;
public MethodBodyIL(MethodBase method)
{
if (method == null)
throw new ArgumentNullException("method");
this.method = method;
}
public Enumerator GetEnumerator()
{
var body = this.method.GetMethodBody();
return new Enumerator(this.method.Module, this.method.DeclaringType.GetGenericArguments(), this.method.GetGenericArguments(), body.GetILAsByteArray(), body.LocalVariables);
}
IEnumerator<ILInstruction> IEnumerable<ILInstruction>.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public struct Enumerator : IEnumerator<ILInstruction>
{
private static readonly IDictionary<short, OpCode> codes = typeof(OpCodes).FindMembers(MemberTypes.Field, BindingFlags.Public | BindingFlags.Static, (m, criteria) => ((FieldInfo)m).FieldType == typeof(OpCode), null).Cast<FieldInfo>().Select(f => (OpCode)f.GetValue(null)).ToDictionary(c => c.Value);
private readonly Module module;
private readonly Type[] genericTypeArguments, genericMethodArguments;
private readonly byte[] il;
private readonly IList<LocalVariableInfo> localVariables;
private int offset;
private ILInstruction current;
internal Enumerator(Module module, Type[] genericTypeArguments, Type[] genericMethodArguments, byte[] il, IList<LocalVariableInfo> localVariables)
{
this.module = module;
this.genericTypeArguments = genericTypeArguments;
this.genericMethodArguments = genericMethodArguments;
this.il = il;
this.localVariables = localVariables;
this.offset = 0;
this.current = default(ILInstruction);
}
public ILInstruction Current
{
get { return this.current; }
}
public bool MoveNext()
{
if (this.offset < this.il.Length)
{
this.current = this.ReadInstruction();
return true;
}
else
{
this.current = default(ILInstruction);
return false;
}
}
public void Reset()
{
this.offset = 0;
this.current = default(ILInstruction);
}
public void Dispose()
{
this.offset = this.il.Length;
this.current = default(ILInstruction);
}
private ILInstruction ReadInstruction()
{
var code = this.ReadCode();
return new ILInstruction(code, this.ReadOperand(code.OperandType));
}
private OpCode ReadCode()
{
var code = codes[this.ReadByte()];
if (code.OpCodeType == OpCodeType.Prefix)
code = codes[(short)(code.Value << 8 | this.ReadByte())];
return code;
}
private object ReadOperand(OperandType operandType)
{
switch (operandType)
{
case OperandType.InlineBrTarget:
case OperandType.InlineI:
case OperandType.InlineSwitch:
return this.ReadInt32();
case OperandType.InlineField:
case OperandType.InlineMethod:
case OperandType.InlineTok:
case OperandType.InlineType:
return this.ReadMember();
case OperandType.InlineI8:
return this.ReadInt64();
case OperandType.InlineNone:
return null;
case OperandType.InlineR:
return this.ReadDouble();
case OperandType.InlineSig:
return this.ReadSignature();
case OperandType.InlineString:
return this.ReadString();
case OperandType.InlineVar:
return this.ReadLocalVariable();
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
return this.ReadByte();
case OperandType.ShortInlineR:
return this.ReadSingle();
case OperandType.ShortInlineVar:
return this.ReadLocalVariableShort();
default:
throw new InvalidOperationException();
}
}
private byte ReadByte()
{
var value = this.il[this.offset];
++this.offset;
return value;
}
private short ReadInt16()
{
var value = BitConverter.ToInt16(this.il, this.offset);
this.offset += sizeof(short);
return value;
}
private int ReadInt32()
{
var value = BitConverter.ToInt32(this.il, this.offset);
this.offset += sizeof(int);
return value;
}
private long ReadInt64()
{
var value = BitConverter.ToInt64(this.il, this.offset);
this.offset += sizeof(long);
return value;
}
private float ReadSingle()
{
var value = BitConverter.ToSingle(this.il, this.offset);
this.offset += sizeof(float);
return value;
}
private double ReadDouble()
{
var value = BitConverter.ToDouble(this.il, this.offset);
this.offset += sizeof(double);
return value;
}
private MemberInfo ReadMember()
{
return this.module.ResolveMember(this.ReadInt32(), this.genericTypeArguments, this.genericMethodArguments);
}
private byte[] ReadSignature()
{
return this.module.ResolveSignature(this.ReadInt32());
}
private string ReadString()
{
return this.module.ResolveString(this.ReadInt32());
}
private LocalVariableInfo ReadLocalVariable()
{
return this.localVariables[this.ReadInt16()];
}
private LocalVariableInfo ReadLocalVariableShort()
{
return this.localVariables[this.ReadByte()];
}
object IEnumerator.Current
{
get { return this.Current; }
}
}
}
public static class ILHelper
{
public static MethodBodyIL GetIL(this MethodBase method)
{
return new MethodBodyIL(method);
}
public static IEnumerable<MethodBase> GetCalledMethods(this Delegate methodPtr)
{
if (methodPtr == null)
throw new ArgumentNullException("methodPtr");
foreach (var instruction in methodPtr.Method.GetIL())
if (IsMethodCall(instruction.Code))
yield return (MethodBase)instruction.Operand;
}
private static bool IsMethodCall(OpCode code)
{
return code == OpCodes.Call || code == OpCodes.Calli || code == OpCodes.Callvirt;
}
}
}
You can use method.Name to get the calling method name.
public static class Invoker
{
public static void invoke(Proxy proxy, Func<Proxy, string> online)
{
//Some caching logic that require the name of the method
//invoked on the proxy (in this specific case "formatSomething")
var methodName = online.Method.Name;
}
}
https://msdn.microsoft.com/en-us/library/system.multicastdelegate%28v=vs.110%29.aspx
Check the following code. If you want to get the method FULL_NAME then write the following in the first line #define FULL_NAME
public class Cache
{
private const uint DefaultCacheSize = 100;
private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();
private readonly object _cacheLocker = new object();
private readonly uint _cacheSize;
public Cache(uint cacheSize = DefaultCacheSize)
{
_cacheSize = cacheSize;
}
public uint CacheSize
{
get { return _cacheSize; }
}
public TValue Resolve<TObj, TValue>(TObj item, Func<TObj, TValue> func, [CallerMemberName] string key = "")
{
#if FULL_NAME
var stackTrace = new StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
key = string.Format("{0}_{1}",
method.DeclaringType == null ? string.Empty : method.DeclaringType.FullName,
method.Name);
#endif
return CacheResolver(item, func, key);
}
private TValue CacheResolver<TObj, TValue>(TObj item, Func<TObj, TValue> func, string key)
{
object res;
if (_cache.TryGetValue(key, out res) && res is TValue)
{
return (TValue) res;
}
TValue result = func(item);
lock (_cacheLocker)
{
_cache[key] = result;
if (_cache.Keys.Count > DefaultCacheSize)
{
_cache.Remove(_cache.Keys.First());
}
}
return result;
}
}
And the usage(from a Form object):
private void CacheTest()
{
var cache = new Cache();
var text = cache.Resolve<Form, string>(this, f => f.Text);
}
I hope it helps you.
EDIT I tested using expressions without performance issues, takes about ~25ms the first time. You can adapt it to Cache class in order to extract the method call expression of the param Expression<Func<T, T1>>.
private string GetExpressionMethodCallName<T, T1>(Expression<Func<T, T1>> exp)
{
var mce = exp.Body as MethodCallExpression;
if (mce == null)
throw new InvalidOperationException("invalid expression");
return mce.Method.Name;
}

Json.Net gives an error when creating my custom JsonConverter

I have a problem whereby I wish to generate a JSON field where the field name is known at runtime e.g.:
{ "known_at_run_time": ["test","test","test"] }
So I tried implementing it this way, yet whenever I run my unit test I get an error saying that that my custom JsonConverter cannot be created. Here is my code:
TermFilter.cs
public enum ExecutionType { plain, fielddata, #bool, and, or }
[JsonObject(MemberSerialization.OptIn)]
public class TermFilter
{
#region PROPERTIES
private JsonTuple query;
private ExecutionType execution;
private string _execution;
private bool _cache;
#endregion
#region CONSTRUCTOR
public TermFilter()
{
try
{
this.query = null;
this.Execution = ExecutionType.plain;
this.Cache = true;
}
catch(Exception)
{
throw;
}
}
public TermFilter(ExecutionType execution)
: this()
{
try
{
this.Execution = execution;
}
catch (Exception)
{
throw;
}
}
public TermFilter(ExecutionType execution, bool cache)
: this(execution)
{
try
{
this.Cache = cache;
}
catch (Exception)
{
throw;
}
}
public TermFilter(string field, string[] terms)
:this()
{
try
{
this.Query = new JsonTuple(field, new HashSet<string>(terms));
}
catch (Exception)
{
throw;
}
}
#endregion
#region GET/SET
//[JsonProperty(ItemConverterType = typeof(JsonTupleConverter))]
//[JsonProperty]
[JsonConverter( typeof(JsonTupleConverter) )]
public JsonTuple Query
{
get { return query; }
set { query = value; }
}
public ExecutionType Execution
{
get { return execution; }
set
{
execution = value;
_execution = value.ToString();
}
}
[JsonProperty(PropertyName = "execution")]
public string _Execution
{
get { return _execution; }
set { _execution = value; }
}
[JsonProperty(PropertyName = "_cache")]
public bool Cache
{
get { return _cache; }
set { _cache = value; }
}
#endregion
#region METHODS
public TermFilter AddTerm(string term)
{
try
{
if (!this.query.Data.Contains(term))
this.query.Data.Add(term);
return this;
}
catch (Exception)
{
throw;
}
}
public string ToJson()
{
try
{
var settings = new JsonSerializerSettings();
settings.TypeNameHandling = TypeNameHandling.Objects;
settings.Converters.Add(new JsonTupleConverter(new Type[] { typeof(JsonTuple) }));
settings.NullValueHandling = NullValueHandling.Ignore;
return JsonConvert.SerializeObject(this, settings);
//return JsonConvert.SerializeObject(this, Formatting.None, new JsonTupleConverter(typeof(JsonTuple)));
//return JsonConvert.SerializeObject(this, Formatting.None, new JsonConverter[] { new JsonTupleConverter(typeof(JsonTuple)), });
}
catch (Exception)
{
throw;
}
}
#endregion
}
JsonTuple.cs
public class JsonTuple
{
#region PROPERTIES
private string field;
private HashSet<string> data;
#endregion
#region CONSTRUCTOR
public JsonTuple()
{
try
{
this.field = null;
this.data = null;
}
catch (Exception)
{
throw;
}
}
public JsonTuple(string field, HashSet<string> data)
{
try
{
this.field = field;
this.data = data;
}
catch (Exception)
{
throw;
}
}
#endregion
#region GET/SET
public string Field
{
get { return field; }
set { field = value; }
}
public HashSet<string> Data
{
get { return data; }
set { data = value; }
}
#endregion
#region METHODS
public string ToJson()
{
try
{
return JsonConvert.SerializeObject(this, Formatting.None, new JsonTupleConverter(typeof(JsonTuple)));
}
catch (Exception)
{
throw;
}
}
#endregion
}
JsonTupleConverter.cs
public class JsonTupleConverter : JsonConverter
{
private readonly Type[] _types;
public JsonTupleConverter(params Type[] types)
{
try
{
_types = types;
}
catch (Exception)
{
throw;
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
try
{
JToken t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else if (!_types.Any(_t => _t == value.GetType()))
{
serializer.Serialize(writer, value);
}
else
{
JsonTuple tuple = (JsonTuple)value;
if ((tuple != null) && (tuple.Field != null) && (tuple.Data != null))
{
JToken entityToken = null;
if (tuple.Data != null)
entityToken = JToken.FromObject(tuple.Data);
JObject o = new JObject();
o.AddFirst(new JProperty(tuple.Field, entityToken));
o.WriteTo(writer);
}
}
}
catch (Exception)
{
throw;
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return _types.Any(t => t == objectType);
}
}
Test.cs
[TestMethod]
public void TermFieldSertialization()
{
try
{
TermFilter filter = new TermFilter("test.field", new string[] {"test1", "test2", "test3"});
Assert.IsNotNull(filter);
string sampleJson = filter.ToJson();
Assert.IsNotNull(sampleJson);
}
catch (Exception)
{
throw;
}
}
What am I doing wrong? Any information will help.
First, try removing the [JsonConverter] attribute from the Query property of your TermFilter class. You don't need it because the Query property is a JsonTuple, and you are already passing an instance of your JsonTupleConverter to the JsonConvert.SerializeObject() method inside your ToJson() method, specifying that it can handle JsonTuples. This will get rid of the error.
However, there is still another issue. It seems that your intent is to get the Query property to serialize to JSON, but as things stand now this will not happen. This is because you have marked your TermFilter class with [JsonObject(MemberSerialization.OptIn)], and the Query property lacks a [JsonProperty] attribute to signal that you want that property to be included in the output. You will need to add [JsonProperty("query")] to fix that. Once you have done that, you should get the output you expect.
As an aside, you don't need to catch exceptions if you only intend to throw them again without doing anything else with them. I see that pattern everywhere in your code. Instead, just leave out the try/catch altogether; it does exactly the same thing and will make your code much more concise. Only catch an exception if you intend to handle it.
I think that your exception is occurring because JsonTupleConverter doesn't have a parameterless constructor.
public JsonTupleConverter() { }
If you add that, the error should go away, but your code might not work because then it'd probably be trying to use a converter without the types set up correctly.
Maybe you should just be serializing it as a dictionary? E.g.
var myDict = new Dictionary<string, List<string>>
{
{ "known_at_run_time", new List<string> { "test","test","test" } }
};
string ser = JsonConvert.SerializeObject(myDict);
// ser is {"known_at_run_time":["test","test","test"]}

switching on type in c# and VB - is this approach stupid?

I have inherited a codebase which contains a lot of upcasting.
I've got tired of all of the switch statements on types with ad-hoc casts inside the code.
I wrote a couple of functions for switching on the type of a variable and getting access to to that variable appropriately cast in the corresponding "case" statement.
As I am relatively new to dot net I thought that perhaps I was coming at it from completely the wrong angle.
If I'm not perhaps this will be useful to someone else.
NB c# specific answers are less useful as the code-base is mostly Visual Basic. I have posted c# code because the c# community is much larger here on stackexchange.
This is an example of the usage:
class Program
{
static void Main(string[] args)
{
List<object> bobbies = new List<object>();
bobbies.Add(new Hashtable());
bobbies.Add(string.Empty);
bobbies.Add(new List<string>());
bobbies.Add(108);
bobbies.Add(10);
bobbies.Add(typeof(string));
bobbies.Add(typeof(string));
bool b = true;
// as an expression
foreach (var bob in bobbies)
Console.WriteLine(
TypeSwitch.on<String>(bob)
.inCase<Hashtable>(x =>
"gotta HASHTABLE")
.inCase<string>(x =>
"its a string " + x)
.inCase<IEnumerable<Object>>(x =>
"I got " + x.Count<Object>().ToString() + " elements")
.inCase<int>(x => (x > 10), x =>
"additional conditions")
.inCase(b, x => {
b = false;
return "non lazy conditions"; })
.otherwise(p =>
"default case"));
// as a statement
foreach (var bob in bobbies)
TypeSwitch.on(bob)
.inCase<Hashtable>(x => Console.WriteLine("one"))
.inCase<String>(x => Console.WriteLine("two"))
.inCase<int>(x => Console.WriteLine("three"))
.otherwise(x => Console.WriteLine("I give up"));
Console.ReadLine();
}
}
and here is the implementation
public static class TypeSwitch
{
public class TypeSwitcher
{
private object _thing;
public TypeSwitcher(object thang) { _thing = thang; }
public TypeSwitcher inCase<TryType>(Func<TryType, bool> guard, Action<TryType> action) {
if (_thing is TryType) {
var t = (TryType)_thing;
if (guard(t)) {
_thing = null;
action(t); } }
return this; }
public TypeSwitcher inCase<TryType>(bool condition, Action<TryType> action) { return inCase<TryType>(p => condition, action); }
public TypeSwitcher inCase<TryType>(Action<TryType> action) { return inCase<TryType>(true, action); }
public TypeSwitcher inCase(bool cond, Action<object> action) { return inCase<object>(cond, action); }
public void otherwise(Action<object> action) { this.inCase<object>(action); }
}
// for case statements with a return value:
public class TypeSwitcherExpression<ResultType>
{
private object _thing;
private ResultType _result;
public ResultType Result { get { return _result; } }
public TypeSwitcherExpression(object thang) { _thing = thang; }
public TypeSwitcherExpression<ResultType> inCase<TryType>(Func<TryType, bool> guard, Func<TryType, ResultType> action) {
if (_thing is TryType) {
var t = (TryType)_thing;
if (guard(t)) {
_thing = null;
_result = action(t); } }
return this; }
public TypeSwitcherExpression<ResultType> inCase<TryType>(bool condition, Func<TryType, ResultType> action) { return inCase<TryType>(p => condition, action); }
public TypeSwitcherExpression<ResultType> inCase<TryType>(Func<TryType, ResultType> action) { return inCase<TryType>(true, action); }
public TypeSwitcherExpression<ResultType> inCase(bool cond, Func<object, ResultType> action) { return inCase<object>(cond, action); }
public ResultType otherwise(Func<object, ResultType> action) { this.inCase<object>(action); return Result; }
}
static public TypeSwitcher on(object thing)
{ return new TypeSwitcher(thing); }
static public TypeSwitcherExpression<ResultType> on<ResultType>(object thing)
{ return new TypeSwitcherExpression<ResultType>(thing); }
public static TypeSwitcher switchOnType(this Object thing)
{ return new TypeSwitcher(thing); }
public static TypeSwitcherExpression<ResultType> switchOnType<ResultType>(this Object thing)
{ return new TypeSwitcherExpression<ResultType>(thing); }
}
Edit 1:
Replaced delegates with Action and Func. Added extension method in case you like that sort of thing.
Edit 2:
Use Is to check type of object
Here is my suggestion
namespace xx{
public static class TypeSwitcher
{
public static dynamic inCase<T>(this object item,Func<dynamic> function)
{
if (item.GetType() == typeof(T))
return function();
else
return "";
}
}
}
using xx;
static void Main(string[] args)
{
List<object> bobbies = new List<object>();
bobbies.Add(new Hashtable());
bobbies.Add(string.Empty);
bobbies.Add(new List<string>());
bobbies.Add(108);
bobbies.Add(10);
bobbies.Add(typeof(string));
bobbies.Add(typeof(string));
foreach (var item in bobbies)
{
Console.WriteLine(item.inCase<Hashtable>(() => "one"));
Console.WriteLine(item.inCase<String>(() => "two"));
Console.WriteLine(item.inCase<int>(() => "three"));
}
Console.ReadLine();
}

c# reference correct parameter type

In Worker.SendMail in the code below, I need to pass a reference of itself to the RetryEmailSend method but am unsure how to reference it. Any help would be appreciated.
public class Worker
{
public bool SendMail()
{
try
{
//implementation
}
catch (Exception ex)
{
RetryEmailSend(NEED REFERENCE TO THIS INSTANCE Worker.SendMail());
}
return true;
}
}
public static class Util
{
public static bool RetryAction(Action action)
{
if (action == null)
throw new ArgumentNullException("action");
try { action(); return true; }
catch
{
return false;
}
}
public static bool RetryEmailSend(NEED INPUT TYPE HERE)
{
return Util.RetryAction(() => INPUT TYPE);
}
}

get return value with DynamicInvoke or generic delegate

i am trying to create a class called SurroundJob that accepts Func
but executing the incoming method is not its purpose, the task of SurroundJob is to do certain predefined things before and after calling the incoming method
however, i am having trouble getting the return value of the incoming method, so that i could pass it to the calling class :(
appended first the calling class,
then the desired, but currently non-functional, 'surrounder' class
and finally the exception due to the inappropriate cast attempt (TResult)method.DynamicInvoke(param)
The Calling Class
class ACoreJob
{
public void DoMyJob()
{
SurroundJob.CoreJobs<Boolean, string> coreJob = DoCoreJob;
Boolean success = false;
SurroundJob.Embed<Boolean, string>(ref success, "facebook.com", coreJob);
if (success) Trace.WriteLine("Wicked without exceptions");
}
Boolean DoCoreJob(string Target)
{
Boolean isHappy = false;
Process.Start(#"http://" + Target);
isHappy = true;
return isHappy;
}
}
The Class in Focus
class SurroundJob
{
public delegate TResult CoreJobs<TResult, T>(T param);
public static void Embed<TResult,T>(ref TResult result,T param, Delegate method)
{
if (method != null)
{
MethodInfo methodInfo = method.Method;
result = default(TResult);
try
{
Log(methodInfo.Name + " Start");
result = (TResult)method.DynamicInvoke(param);
}
catch (Exception e)
{
Troubleshoot(methodInfo.Name, e);
}
}
}
The Exception
At line: result = (TResult)method.DynamicInvoke(param);
DoCoreJob Problem: Unable to cast object of type 'ACoreJob' to type 'Boolean'.
i am new to this world and dont really know how to interact with DynamicInvoke in order to get the return value?
or is there another way to achieve my aim?
thank you sincerely!
Here's a simple example using Func<T, TResult>:
void Main()
{
bool success = false;
SurroundJob.Embed(ref success, "facebook.com", DoCoreJob);
}
Boolean DoCoreJob(string Target)
{
Boolean isHappy = false;
Console.WriteLine(#"http://" + Target);
isHappy = true;
return isHappy;
}
class SurroundJob
{
public static void Embed<T, TResult>(ref TResult Result, T param, Func<T, TResult> method)
{
if(method != null)
{
try
{
Log(param.ToString());
Result = method(param);
}
catch(Exception e)
{
Troubleshoot(param.ToString(), e);
}
}
}
public static void Log(string s)
{
Console.WriteLine("Log: " + s);
}
public static void Troubleshoot(string s, Exception e)
{
Console.WriteLine("Troubleshoot: " + s);
Console.WriteLine(e.ToString());
}
}

Categories

Resources