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;
}
Related
I need to create an interface with 2 type and use it as a method return value.
public interface StringLong<T1,T2>
where T1 : string
where T2 : long
{}
StringLong<T1,T2> method StringLong<T1,T2>()
It makes no sense to define an interface with two generic types that you constrain to just string and long.
It sounds like you just want a tuple:
(string, long) MyMethod()
{
return ("Hello", 42L);
}
You can even name the return values:
(string message, long meaningOfLife) MyMethod()
{
return ("Hello", 42L);
}
Then you can write:
var result = MyMethod();
Console.WriteLine(result.message);
Console.WriteLine(result.meaningOfLife);
I think is the functionality you are trying to achieve (from the comments). Since the return might be of either string or long there common ancestor is object.
Once you have the value you can use pattern matching to cast the result into the appropriate type:
static class Program
{
static void Main(string[] args)
{
var obj = MethodReturnsStringOrLong(1722);
switch (obj)
{
case string str:
Console.WriteLine($"String is {str}");
break;
case long lng:
Console.WriteLine($"Long is {lng}");
break;
default:
throw new NotSupportedException();
}
}
public static object MethodReturnsStringOrLong(int input)
{
if (input % 2 == 0)
{
return 1928374028203384L;
}
else
{
return "ASIDJMFHSOASKSJHD";
}
}
}
An alternative is the create your own common ancestor, like the class Value below that might contains either a long and/or a string.
public class Value
{
public Value(long longValue)
{
LongValue = longValue;
}
public Value(string stringValue)
{
StringValue = stringValue;
}
public long? LongValue { get; }
public string StringValue { get; }
}
static class Program
{
static void Main(string[] args)
{
var obj = MethodReturnsStringOrLong(1722);
if (obj.LongValue.HasValue)
{
Console.WriteLine($"Long is {obj.LongValue.Value}");
}
if (!string.IsNullOrEmpty(obj.StringValue))
{
Console.WriteLine($"String is {obj.StringValue}");
}
}
public static Value MethodReturnsStringOrLong(int input)
{
if (input % 2 == 0)
{
return new Value(1928374028203384L);
}
else
{
return new Value("ASIDJMFHSOASKSJHD");
}
}
}
A function that returns a value:
public object ReturnValue() { return new object(); }
Func<object> funcReturnValue = ReturnValue;
A function that retuns a function that returns a value:
public Func<object> ReturnFunc() { return ReturnValue; }
Func<Func<object>> funcReturnFunc = ReturnFunc;
So far, so good. I'm having trouble with a function that returns itself:
public *something* ReturnSelf() { return ReturnSelf; }
Func<*something*> funcReturnSelf = ReturnSelf;
Clearly, *something* is going to be a Func<T> of some kind, but I'm not sure what.
At first glance I guess it's going to be infinity recursive, since ReturnSelf
returns a function that returns a function that returns a function...
Context: A state machine using functions for states. It works fine using
a class variable to keep the current state:
private Action _currentState;
private void StateOne() {
if (IsTuesday) {
_currentState = StateTwo;
}
}
prvivate void StateTwo() {
if (IsRaining) {
_currentState = StateOne;
}
}
private void StateEngine() {
while (true) {
_currentState();
// set tuesday/raining/etc.
}
}
...but that feels too much like keeping state in a global.
I'd far prefer something closer to:
private Func<*somthing*> StateOne() {
if (IsTuesday) {
return StateTwo;
} else {
return StateOne;
}
}
prvivate Func<*something*> StateTwo() {
if (IsRaining) {
return StateOne;
} else {
return StateTwo;
}
}
private void StateEngine() {
Func<*something*> currentState = StateOne;
while (true) {
Func<*something*> nextState = currentState();
// set tuesday/raining/etc.
currentState = nextState;
}
}
Any ideas? Or should I just stick with the working solution?
Instead of using Func<T> you could define a delegate which returns a value of that delegate type. Delegates can be used to pass function references as arguments to another function, or in this case to return a function reference from a function (docs).
Example:
class Program
{
private delegate StateDelegate StateDelegate();
public static void Main(string[] args)
{
Program program = new Program();
StateDelegate stateHandler = program.HandleStateOne;
// Execute HandleStateOne, returns HandleStateTwo
stateHandler = stateHandler.Invoke();
// Execute HandleStateTwo, returns reference to HandleStateOne
stateHandler = stateHandler.Invoke();
}
private StateDelegate HandleStateOne()
{
// Do something state specific...
return HandleStateTwo;
}
private StateDelegate HandleStateTwo()
{
// Do something state specific...
return HandleStateOne;
}
// Literally return reference to the function itself
private StateDelegate ReturnSelf()
{
return ReturnSelf;
}
}
You can do this with the help of an extra type:
class State
{
private Func<State> _func;
public State(Func<State> func)
{
_func = func;
}
public State Invoke() => _func();
}
And then you can write:
bool IsTuesday = false;
bool IsRaining = false;
State StateOne = null;
State StateTwo = null;
StateOne = new State
(
() =>
{
if (IsTuesday) {
return StateTwo;
} else {
return StateOne;
}
}
);
StateTwo = new State
(
() =>
{
if (IsRaining) {
return StateOne;
} else {
return StateTwo;
}
}
);
And, of course:
void StateEngine() {
State currentState = StateOne;
while (true) {
var nextState = currentState.Invoke();
// set tuesday/raining/etc.
currentState = nextState;
}
}
We may do a little more, with an implicit conversion to Func<State> (and then you don't need an invoke method anymore):
public static implicit operator Func<State> (State state)
{
return state._func;
}
Then you can write:
void StateEngine() {
Func<State> currentState = StateOne;
while (true) {
Func<State> nextState = currentState();
// set tuesday/raining/etc.
currentState = nextState;
}
}
So, Func<State> returns something that can be converted implicitly into Func<State>.
Code in SharpLap
I want to generate the right object with one code line and not a switch case because always when a new device is added I have to add a new line.
Is it possible to do that in one line without switch case?
public static Device GetDevice(Device.enumDevice TypeOfDevice, string alias)
{
// Create the Object with using reflection
switch (TypeOfDevice)
{
case Device.enumDevice.A34411:
return new A34411(string alias);
break;
case Device.enumDevice.N5744:
return new N5744(string alias);
break;
default:
throw new NotImplementedException();
}
return null;
}
You could store the factory methods as delegates in a dictionary
private static Dictionary<Device.enumDevice, Func<string, Device>> _factoryDict =
new Dictionary<Device.enumDevice, Func<string, Device>>{
[Device.enumDevice.A34411] = (alias) => new A34411(alias),
[Device.enumDevice.N5744] = (alias) => new N5744(alias),
};
...
public static Device GetDevice(Device.enumDevice TypeOfDevice, string alias)
{
if (_factoryDict.TryGetValue(TypeOfDevice, out var factory)) {
return factory(alias);
}
throw new NotImplementedException();
// No retun statement here, as it would be unreachable because of the throw statement.
}
Or, using reflection:
const string deviceNameSpace = "MyName.MyProject.Devices.";
public static Device GetDevice(Device.enumDevice deviceType, string alias)
{
string typeName = deviceNameSpace + deviceType.ToString();
Type type = Type.GetType(typeName, throwOnError: true);
return (Device)Activator.CreateInstance(type, alias);
}
An elegant approach would be to use Dependency Injection with "Named Type Registrations"
Fast, but not quite a complete example:
public abstract class Device
{
protected Device(string alias)
{
Alias = alias;
}
public string Alias { get; }
}
public class A1 : Device
{
public A1(string alias) : base(alias) { }
}
public class A2 : Device
{
public A2(string alias) : base(alias) { }
}
class DeviceAttribute : Attribute
{
public DeviceAttribute(Type type)
{
Type = type;
}
public Type Type { get; }
}
public enum DeviceEnum
{
[Device(typeof(A1))]
A1,
[Device(typeof(A2))]
A2
}
public static class DeviceEnumExtension
{
public static Device GetInstance(this DeviceEnum obj, string alias)
{
var member = typeof(DeviceEnum).GetMember(obj.ToString());
if (member[0].GetCustomAttributes(typeof(DeviceAttribute), false)[0] is DeviceAttribute deviceAttr)
{
var ctor = deviceAttr.Type.GetConstructor(new[] {typeof(string)});
return ctor.Invoke(new object[] {alias}) as Device;
}
return null;
}
}
public class UnitTest1
{
[Fact]
public void Test1()
{
// Arrange
var a1 = DeviceEnum.A1;
var a2 = DeviceEnum.A2;
// Act
var instanceA1 = a1.GetInstance("A1");
var instanceA2 = a2.GetInstance("A2");
// Assert
Assert.Equal(typeof(A1), instanceA1.GetType());
Assert.Equal(typeof(A2), instanceA2.GetType());
Assert.Equal("A1", instanceA1.Alias);
Assert.Equal("A2", instanceA2.Alias);
}
}
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();
}
Would some kind person help me sort out the output of .Net Reflector v6.5 that does not compile? I think that the symbols are out of whack but global search and replace might fix that. I don't get the odd class definition. Ideas?
[CompilerGenerated]
private sealed class <ApplicationTaskIterator>d__0 : IEnumerable<ApplicationTask>, IEnumerable, IEnumerator<ApplicationTask>, IEnumerator, IDisposable
{
private int <>1__state;
private ApplicationTask <>2__current;
public SessionMetrics <>3__sm;
public Dictionary<int, ThreadMetrics> <>7__wrap3;
public Dictionary<int, ThreadMetrics>.ValueCollection.Enumerator <>7__wrap4;
public ApplicationTask <currentTask>5__1;
public ThreadMetrics <tm>5__2;
public SessionMetrics sm;
[DebuggerHidden]
public <ApplicationTaskIterator>d__0(int <>1__state)
{
this.<>1__state = <>1__state;
}
private bool MoveNext()
{
try
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
Monitor.Enter(this.<>7__wrap3 = ThreadMetrics._allThreadMetrics);
this.<>1__state = 1;
this.<>7__wrap4 = ThreadMetrics._allThreadMetrics.Values.GetEnumerator();
this.<>1__state = 2;
while (this.<>7__wrap4.MoveNext())
{
this.<tm>5__2 = this.<>7__wrap4.Current;
if ((((this.<tm>5__2._managedThread.ThreadState == System.Threading.ThreadState.Stopped) || object.ReferenceEquals(this.<tm>5__2._managedThread, Thread.CurrentThread)) || ((this.<currentTask>5__1 = this.<tm>5__2.CurrentApplicationTask) == null)) || ((this.sm != null) && !this.<currentTask>5__1.CurrentSessionMetrics.SessionGUID.Equals(this.sm.SessionGUID)))
{
continue;
}
this.<currentTask>5__1.Active = !this.<tm>5__2.Suspended;
this.<>2__current = this.<currentTask>5__1;
this.<>1__state = 3;
return true;
Label_010C:
this.<>1__state = 2;
}
this.<>1__state = 1;
this.<>7__wrap4.Dispose();
this.<>1__state = -1;
Monitor.Exit(this.<>7__wrap3);
break;
case 3:
goto Label_010C;
}
return false;
}
fault
{
((IDisposable) this).Dispose();
}
}
}
Used like this:
internal static IEnumerable<ApplicationTask> ApplicationTaskIterator(SessionMetrics sm)
{
return new <ApplicationTaskIterator>d__0(-2) { <>3__sm = sm };
}
That's simply what the C# compiler transforms a method containing yield return statements to.
If you want to make the code compile, you can either try to decipher what the method is doing and recreate the original version with yield return statements; or you can rename the class and all members to valid C# names.
The original method probably looked like this:
internal static IEnumerable<ApplicationTask> ApplicationTaskIterator(SessionMetrics sm)
{
lock (ThreadMetrics._allThreadMetrics)
{
foreach (var tm in ThreadMetrics._allThreadMetrics.Values)
{
if (tm._managedThread.ThreadState != ThreadState.Stopped)
{
if (!object.ReferenceEquals(tm._managedThread, Thread.CurrentThread))
{
ApplicationTask currentTask;
if ((currentTask = tm.CurrentApplicationTask) != null)
{
if (sm == null || !currentTask.CurrentSessionMetrics.SessionGUID.Equals(sm.SessionGUID))
{
currentTask.Active = !tm.Suspended;
yield return currentTask;
}
}
}
}
}
}
}