How to create a dictionary of string and delegate in C# [duplicate] - c#

In regards to the answer for this question Passing DataContext into Action(), how do I return a value from action(db)?
SimpleUsing.DoUsing(db => {
// do whatever with db
});
Should be more like:
MyType myType = SimpleUsing.DoUsing<MyType>(db => {
// do whatever with db. query buit using db returns MyType.
});

You can use Func<T, TResult> generic delegate. (See MSDN)
Func<MyType, ReturnType> func = (db) => { return new MyType(); }
Also there are useful generic delegates which considers a return value:
Converter<TInput, TOutput> (MSDN)
Predicate<TInput> - always return bool (MSDN)
Method:
public MyType SimpleUsing.DoUsing<MyType>(Func<TInput, MyType> myTypeFactory)
Generic delegate:
Func<InputArgumentType, MyType> createInstance = db => return new MyType();
Execute:
MyType myTypeInstance = SimpleUsing.DoUsing(
createInstance(new InputArgumentType()));
OR explicitly:
MyType myTypeInstance = SimpleUsing.DoUsing(db => return new MyType());

Your static method should go from:
public static class SimpleUsing
{
public static void DoUsing(Action<MyDataContext> action)
{
using (MyDataContext db = new MyDataContext())
action(db);
}
}
To:
public static class SimpleUsing
{
public static TResult DoUsing<TResult>(Func<MyDataContext, TResult> action)
{
using (MyDataContext db = new MyDataContext())
return action(db);
}
}
This answer grew out of comments so I could provide code. For a complete elaboration, please see #sll's answer below.

Use Func<T> rather than Action<T>.
Action<T> acts like a void method with parameter of type T, while Func<T> works like a function with no parameters and which returns an object of type T.
If you wish to give parameters to your function, use Func<TParameter1, TParameter2, ..., TReturn>.

You can also take advantage of the fact that a lambda or anonymous method can close over variables in its enclosing scope.
MyType result;
SimpleUsing.DoUsing(db =>
{
result = db.SomeQuery(); //whatever returns the MyType result
});
//do something with result

In addition to ssls answer: For a software we call a lot of "micro methods" to query this and that from the local machine. Sometimes exceptions appear (file / folder not existing, etc). In order to not repeat our self over and over with try/catch blocks, we used ssls approach with return values:
private T ExecuteAndCatch<T>(Func<T> action, T defaultReturn)
{
try
{
return action();
}
catch (Exception ex)
{
Log.e("Exception during ExecuteAndCatch", ex);
return defaultReturn;
}
}
Example of mentioned micro-methods:
private Boolean CheckKasperskyInstalled() => System.IO.File.Exists(Environment.ExpandEnvironmentVariables(#"%pf_x86%\Kaspersky Lab\Kaspersky Endpoint Security for Windows\avp.exe"));
private Boolean CheckKasperskyRunning() => System.Diagnostics.Process.GetProcessesByName("avp").Length > 0;
And when using, we no longer have to care if these Methods might throw an exception for whatever reason:
cci = new ComputerComplianceInfo();
cci.KasperskyInstalled = ExecuteAndCatch(() => CheckKasperskyInstalled(), false);
cci.KasperskyRunning = ExecuteAndCatch(() => CheckKasperskyRunning(), false);

Related

How can I pass several methods (with parameters) AS a parameter?

Suppose I have the following WCF code:
try
{
ServiceClient proxy = new ServiceClient();
proxy.ClientCredentials.UserName.UserName = "user";
proxy.ClientCredentials.UserName.Password = "password";
proxy.GetData(2);
if (proxy.State = CommunicationState.Opened)
{
proxy.GetData("data");
}
proxy.Close();
}
catch (FaultException ex)
{
// handle the exception
}
And since I notice that the try...catch and other logic is repetitive, not to mention that setting up a WCF call is expensive, I want to send many "methods and parameters" to this function.
In essence pass GetData(2) and GetData("data") as a method array, and have the results return either asynchronously or synchronously.
How would I accomplish this?
I suppose I could have two 'ref' objects to handle the results[] and a shared lock to the results[]. However I'm not sure how to pass "methods with parameters" as a parameter to another function.
Perhaps another way of looking at this might be an array of function pointers, to the same function with different params.
Can anyone nudge me into the right way of doing this?
More info:
I am asking this question so I can optimize this approach to handling WCF exceptions and retries but so I don't have to always open/close the client after each call.
Use delegates and pass them in a list.
The C# Func<T> delegate is used when a return value is needed.
List<Func<Data>> funcList = new List<Func<Data>>();
funcList.Add( () => GetData(2) );
// You can use any condition as you otherwise would to add to the list.
if (proxy.State = CommunicationState.Opened)
{
funcList.Add( () => GetData("data") );
}
List<Data> ProcessFuncs(List<Func<Data>> funcDatas)
{
List<Data> returnList = new List<Data>();
foreach(var func in funcDatas)
{
returnList.Add(func());
}
}
( as long as the return types are identical, this will work )
This is just an example of course; if your methods don't return anything, you can use the C# Action delegate, which just executes an action and doesn't return any value.
List<Action> actionList = new List<Action>();
actionList.Add( () => ProcessData("data")); // ProcessData is a void with no return type
actionList.Add( () => ProcessData(2));
public void ProcessActions(List<Action> actions)
{
foreach(var action in actions)
{
action();
}
}
In response to some comments:
This code compiles and is all equivalent:
class Program
{
public static string GetData(string item) { return item; }
public static string GetData(int item) { return item.ToString(); }
static void Main(string[] args)
{
string someLocalVar = "what is it?";
int someLocalValueType = 3;
Func<string> test = () =>
{
return GetData(someLocalVar);
};
Func<string> test2 = () => GetData(someLocalValueType);
someLocalValueType = 5;
List<Func<string>> testList = new List<Func<string>>();
testList.Add(() => GetData(someLocalVar));
testList.Add(() => GetData(2));
testList.Add(test);
testList.Add(test2);
someLocalVar = "something else";
foreach(var func in testList)
{
Console.WriteLine(func());
}
Console.ReadKey();
}
}
Result is:
I wouldn't use delegates here because then you are constrained by types and to solve that it becomes horrible and over-complicated. I would just have a callback that gives you free reign over the ServiceClient once it has been set up. I think this is a pattern that has a name but I don't know.
interface IProxyActionCallback
{
void DoProxyStuff(ServiceClient proxy);
}
void MyMethod(IProxyActionCallback callback)
{
try
{
ServiceClient proxy = new ServiceClient();
proxy.ClientCredentials.UserName.UserName = "user";
proxy.ClientCredentials.UserName.Password = "password";
callback.DoProxyStuff(proxy);
proxy.Close();
}
catch (FaultException ex)
{
// handle the exception
}
}
Then you call the method like:
MyMethod(new DoSpecificStuff());
Where DoSpecificStuff is a class that implements the interface and allows you to do specific calls with the proxy:
class DoSpecificStuff : IProxyActionCallback
{
public void DoProxyStuff(ServiceClient proxy)
{
proxy.GetData(2);
if (proxy.State = CommunicationState.Opened)
{
proxy.GetData("data");
}
}
}
So you'd have tons of classes that implement the interface, and they all "share" the same try-catch boiler-plate proxy stuff which is in one place.
Bellow is an example of how to make a collection of delegates and their arguments then invoke them later on without knowing the methods definition. As far as I know if you want to invoke methods with different definitions in a single general call you have to do something like this.
List<Tuple<delegate, object[]>> delegates = new List<Tuple<delegate, object[]>>();
delegates.Add(new Tuple<delegate, object[]>(new Func<Arg1Type, Arg2Type, ReturnType>(MyFunctionName), new object[] { arg1, arg2 });
foreach (Tuple<delegate, object[]> d in delegates)
{
d.Item1.DynamicInvoke(d.Item2);
}
You could use C# delegates:
A delegate is a type that represents references to methods with a
particular parameter list and return type. When you instantiate a
delegate, you can associate its instance with any method with a
compatible signature and return type. You can invoke (or call) the
method through the delegate instance. Delegates are used to pass
methods as arguments to other methods. Event handlers are nothing more
than methods that are invoked through delegates. You create a custom
method, and a class such as a windows control can call your method
when a certain event occurs. The following example shows a delegate
declaration:
More on this:
http://msdn.microsoft.com/en-us/library/ms173171.aspx
You can pass functions with parameters this way:
public void strategy<R, T1, T2>(Func<R, T1, T2> f);
public bool predicate(string a, string b);
strategy<bool, string, string>(predicate);
The first line declares the function strategy() accepting a function f;
That function return the type R and takes two parameters of type T1 and T2.
The second line defines a function that returns a bool and accepts two string.
The third line invokes the strategy passing it the predicate as a parameter.
Not sure to understand what you're trying to achieve, but basically if your service exposes a GetData(int) method and a GetData(string) method as well as an async proxy, you should call both asynchronously using something like:
var getData = proxy.GetDataAsync(2);
var getData2 = proxy.GetDataAsync("data");
await Task.WhenAll(getData, getData2);
// Gets the result using getData.Result...etc.

Setting parameter values of anonymous function in C#

Lets say i have the following code
private Func<T> _method;
public void SetExecutableMethod<T>(Func<T> methodParam)
{
_method = methodParam;
}
public T ExecuteMethod(object[] parameterValues)
{
//get the number of parameters _method has;
var methodCallExpression = _method.Body as MethodCallExpression;
var method = methodCallExpression.Method;
ParameterInfo[] methodParams = method.GetParameters();
//So i now have a list of parameters for the method call,
//How can i update the parameter values for each of these?
for (int i = 0; i < parameters.Count(); i++ )
{
methodParams[i] = ???''
}
return _method.Compile()();
}
public void InitAndTest()
{
SetExecutableMethod( () => _service.SomeMethod1("param1 placeholder", "param2 placeholder") );
T result1 = ExecuteMethod(new object[]{"Test1", "Test2"});
T result2 = ExecuteMethod(new object[]{"Test3", "Test4"}););
}
In the above code, i want to set a private variable to some Func that points to an anonymoust function and never have to set it again.
I then would like to be able to call ExecuteMethod(...) with different parameters. This method should update the parameter values of the variable _method and then invoke the method.
I can read the number of parameters and their values fine, i just am not sure how to set the values for those parameter? Any thoughts on this?
This is not the way to do it. Right now, your _method field is a delegate of type Func<T>, and you expect that its body contains yet another method which is actually executed. That is a lot to expect from your callers. I would forget about this approach and look for something different.
One way would be to supply a method which takes an array of objects as its parameter (Func<object[], T>), and then invoke it directly with appropriate parameters (but never a method in its body). Even this is less common for a strongly typed language like C# since you lose all type safety (but then again, you do want to be pretty flexible with this framework you are designing).
The other way would be to get a MethodInfo instance, and then use its Invoke method. In a way, this might even express your intents better, because it will be obvious that the executable method is capable of virtually anything.
Next, you could use generics to get some type safety, and require that all your input parameters are wrapped inside a single parameter class. In that case, you might have a strongly typed Func<Tparam, Tresult> method, and your Execute method would accept a Tparam instance as its parameter. This would void the need for any reflection.
[Edit]
As I wrote, I would try to avoid reflection. Since you wrote you basically need a cache of method results, a simple approach might be something like:
Create a wrapper for your list of parameters so that you can compare them "by value". I added an example class, but you might even want to allow passing an IEqualityComparer explicitly, so that you don't have to override Equals for each partial parameter.
// implements `IEquatable` for a list of parameters
class Parameters : IEquatable<Parameters>
{
private readonly object[] _parameters;
public Parameters(object[] parms)
{
_parameters = parms;
}
#region IEquatable<Parameters> Members
public bool Equals(Parameters other)
{
if (other == null)
return false;
if (_parameters.Length != other._parameters.Length)
return false;
// check each parameter to see if it's equal
// ...
}
public override bool Equals(object obj)
{
return Equals(obj as Parameters);
}
public override int GetHashCode()
{ ... }
#endregion
}
Create a cache for a single service. Using the wrapper class above, it should simply check if a cached result exists:
// contains cached results for a single service
class CachedCallInfo
{
private readonly Func<object[], object> _method;
private readonly Dictionary<Parameters, object> _cache
= new Dictionary<Parameters, object>();
public CachedCallInfo(Func<object[], object> method)
{
_method = method;
}
public T GetResult<T>(params object[] parameters)
{
// use out Parameters class to ensure comparison
// by value
var key = new Parameters(parameters);
object result = null;
// result exists?
if (!_cache.TryGetValue(key, out result))
{
// do the actual service call
result = _method(parameters);
// add to cache
_cache.Add(key, result);
}
return (T)result;
}
}
Create the final class which will reference services by name:
public class ServiceCache
{
private readonly Dictionary<string, CachedCallInfo> _services =
new Dictionary<string, CachedCallInfo>();
public void RegisterService(string name, Func<object[], object> method)
{
_services[name] = new CachedCallInfo(method);
}
// "params" keyword is used to simplify method calls
public T GetResult<T>(string serviceName, params object[] parameters)
{
return _services[serviceName].GetResult<T>(parameters);
}
}
Your cache setup will then look like this:
serviceCache.RegisterService("ServiceA", #params => DoSomething(#params));
serviceCache.RegisterService("ServiceB", #params => SomethingElse(#params));
And you would simply call it like this:
var result = serviceCache.GetResult("ServiceA", paramA, paramB, paramC);
Not sure why this is useful, but here goes:
public class SomeCrazyClass<T>
{
private Expression<Func<T>> _method;
public void SetExecutableMethod(Expression<Func<T>> methodParam)
{
_method = methodParam;
}
public object ExecuteMethod(SomeService someService, object[] parameterValues)
{
var methodCallExpression = _method.Body as MethodCallExpression;
var method = methodCallExpression.Method;
var methodCall = Expression.Call(Expression.Constant(someService), method,
parameterValues.Select(Expression.Constant));
return Expression.Lambda(methodCall).Compile().DynamicInvoke();
}
}
Call it like so:
public static void InitAndTest()
{
var something = new SomeCrazyClass<int>(); //or whatever type your method returns
var _service = new SomeService();
something.SetExecutableMethod(() => _service.SomeMethod1("param1 placeholder", "param2 placeholder"));
var result1 = something.ExecuteMethod(_service,new object[] {"Test1", "Test2"});
var result2 = something.ExecuteMethod(_service, new object[] {"Test3", "Test4"});
}
Personally, I think you're going WAY overboard, unless there is an overriding architecture need to deal with the lambda as an expression tree. But, I digress.
Instead of working with the reflective elements (which are basically for description only in terms of an expression tree), look at the Arguments member of your MethodCallExpression. It will contain several ContantExpression objects, which you can replace with your own ConstantExpressions containing the string values you want to pass in. However, Expressions are read-only; you have to rebuild an equivalent tree for this call.
public class FuncManipulator<T>
{
private Func<T> _method;
public void SetExecutableMethod(Func<T> methodParam)
{
_method = methodParam;
}
//you forgot the "params" keyword
public T ExecuteMethod(params object[] parameterValues)
{
//get the number of parameters _method has;
var methodCallExpression = _method.Body as MethodCallExpression;
var arguments = methodCallExpression.Arguments;
var newArguments = new List<Expression>();
for (int i = 0; i < arguments.Count(); i++ )
{
newArguments.Add(Expression.Constant(parameterValues[i]));
}
//"Clone" the expression, specifying the new parameters instead of the old.
var newMethodExpression = Expression.Call(methodCallExpression.Object,
methodCallExpression.Method,
newArguments)
return newMethodExpression.Compile()();
}
}
...
public void InitAndTest()
{
SetExecutableMethod( () => _service.SomeMethod1("param1 placeholder", "param2 placeholder") );
T result1 = ExecuteMethod("Test1", "Test2");
T result2 = ExecuteMethod("Test3", "Test4");
T result3 = ExecuteMethod("Test6", "Test5");
}
This will work as long as the expression tree can find the Func referred to by MethodCallExpression.method within the current instance.
However, I think there's a much simpler way:
public class FuncManipulator<T>
{
private Func<T> _method;
public void SetExecutableMethod(Func<T> methodParam)
{
_method = methodParam;
}
//you must pass the actual array; we are creating a closure reference that will live
//as long as the delegate
public void SetMethodParams(object[] param)
{
_param = param;
}
public T ExecuteMethod(params object[] passedParam)
{
//We have to re-initialize _param based on passedParam
//instead of simply reassigning the reference, because the lambda
//requires we don't change the reference.
for(int i=0; i<_param.Length; i++)
_param[i] = passedParam.Length <= i ? null : passedParam[i];
//notice we don't pass _param; the lambda already knows about it
//via the reference set up when declaring the lambda.
return _method();
}
}
...
public void InitAndTest()
{
//this is an "external closure" we must keep in memory
object[] param = new object[2];
SetExecutableMethod( () => _service.SomeMethod1(param[0], param[1]) );
//We do so by passing the reference to our object
SetMethodParams(param);
//now, don't ever reassign the entire array.
//the ExecuteMethod function will replace indices without redefining the array.
T result1 = ExecuteMethod("Test1", "Test2");
T result2 = ExecuteMethod("Test3", "Test4");
T result3 = ExecuteMethod("Test6", "Test5");
}

Creating a genericly typed Action<> at runtime

Is it possible to create a generically typed Action at run time based on some specified types? In this particular scenario, the body of the Action will ultimately ignore the argument types, as the typed Action<> will just be a wrapper around a no-argument Action, e.g.
Action original = () => { };
...
Action<TType> wrapper = (arg) => {
original();
}
Or, even:
Action<TTypeA, TTypeB> wrapper = (arg) => {
original();
}
As you can see, the body of the typed Action<> ignores the arguments, and their type, it's just acting as a wrapper.
If you're curious as to why I want create this wrapper in the first place, the 'basic' version is that I am ultimately converting the Action to a Delegate for doing a Delegate.Combine(), which requires identical types. All I am trying to accomplish with the Delegate.Combine() is a basic notification that the delegate was fired.
At this point I will probably re-work my design to avoid these types of shenanigans, but I am still very curious how this might be accomplished.
The closest I could get was the following:
private static TType GetTypedDelegate<TType>(Action onComplete)
where TType : class
{
MethodInfo info = typeof(TType).GetMethod("Invoke");
ParameterInfo[] parameters = info.GetParameters();
object result;
if (parameters.Length == 0)
result = onComplete;
else if (parameters.Length == 1)
result = GetTypedDelegate<TType>(onComplete, parameters[0].ParameterType);
// etc
TType onCompleteCasted = Delegate.CreateDelegate(typeof(TType), result, "Invoke") as TType;
return onCompleteCasted;
}
private static Delegate GetTypedDelegate<TType>(Action onComplete, Type type)
{
// This line isn't useful for me right now, since I can't just create a new
// instance of the action with a parameterless constructor ... but I thought I'd throw it in here in case it was of use
Type actionType = typeof(Action<>).MakeGenericType(new[] { type });
// Do some magic here with the type information
// The following of course does not work,but you get the idea of what I am aiming for
Action<type> wrapper = (arg1) =>
{
onComplete();
};
return wrapper as Delegate;
}
I think that the easiest option is to write a generic method and then invoke it dynamically (using Reflection or possibly even using C# 4 dynamic):
class Helper {
public static Action<TType> Wrap1<TType>(Action arg) {
return (arg) => { original(); }
}
}
Invoking the method using Reflection and using typ1 as the generic type argument could look like this:
var meth = typeof(Helper).GetMethod("Wrap1");
var gmeth = meth.MakeGenericMethod(new[] { typ1 });
var genericAction = gmeth.Invoke(null, new object[] { action });
If you don't want to use reflection you can setup some classes like this.
public class ActionWrapper<TTypeA>
{
protected readonly Action _original;
public ActionWrapper(Action original)
{
_original = original;
}
public Action<TTypeA> Wrapped { get { return WrappedAction; } }
private void WrappedAction(TTypeA a)
{
_original();
}
}
public class ActionWrapper<TTypeA,TTypeB>:ActionWrapper<TTypeA>
{
public ActionWrapper(Action original) : base(original)
{
}
public new Action<TTypeA, TTypeB> Wrapped { get { return WrappedAction; } }
private void WrappedAction(TTypeA a,TTypeB b)
{
_original();
}
}

How do I get the custom attributes of a method from Action<T>?

How can I get the custom attributes of a method from a Action<T> delegate?
Example:
//simple custom attribute
public class StatusAttribute : Attribute
{
public string Message { get; set; } = string.Empty;
}
// an extension methodto wrap MethodInfo.GetCustomAttributes(Type, Bool) with
// generics for the custom Attribute type
public static class MethodInfoExtentions
{
public static IEnumerable<TAttribute> GetCustomAttributes<TAttribute>(this MethodInfo methodInfo, bool inherit) where TAttribute : Attribute
{
object[] attributeObjects = methodInfo.GetCustomAttributes(typeof(TAttribute), inherit);
return attributeObjects.Cast<TAttribute>();
}
}
// test class with a test method to implment the custom attribute
public class Foo
{
[Status(Message="I'm doing something")]
public void DoSomething()
{
// code would go here
}
}
// creates an action and attempts to get the attribute on the action
private void CallDoSomething()
{
Action<Foo> myAction = new Action<Foo>(m => m.DoSomething());
IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true);
// Status Attributes count = 0? Why?
}
I realize I could do this by using reflection on Foo, but for what I'm trying to create I have to use an Action<T>.
The problem is that the action doesn't directly point at Foo.DoSomething. It points at a compiler-generated method of the form:
private static void <>__a(Foo m)
{
m.DoSomething();
}
One option here would be to change it to an Expression<Action<T>>, then you can dissect the expression tree afterwards and extract the attributes:
Expression<Action<Foo>> myAction = m => m.DoSomething();
var method = ((MethodCallExpression)myAction.Body).Method;
var statusAttributes = method.GetCustomAttributes<StatusAttribute>(true);
int count = statusAttributes.Count(); // = 1
The issue is that the lambda m => m.DoSomething() is not the same as DoSomething. It is a lambda expression which gets compiled into a method call on a compiler-generated method, possibly using a compiler-generated type (though maybe not the latter, since there are no captured local variables).
A very verbose way of getting an Action<Foo> from an instance (non-static) method of the Foo type is this:
var myAction = (Action<Foo>)Delegate.CreateDelegate(
typeof(Action<Foo>),
null, // treat method as static, even though it's not
typeof(Foo).GetMethod("DoSomething", BindingFlags.Instance | BindingFlags.Public)
);
Obviously, that is far from ideal and probably in fact useless in your case; but it's worth knowing ;)
Update: Actually, it just occurred to me you could write a quick extension method to make this easy for any instance method that you want to wrap as a static method (and maintain the "correct" MethodInfo):
public static class ActionEx
{
public static Action<T> ToStaticMethod<T>(this Action action)
{
if (!(action.Target is T))
{
throw new ArgumentException("Blah blah blah.");
}
return (Action<T>)Delegate.CreateDelegate(
typeof(Action<T>),
null,
action.Method
);
}
}
This would allow you to do:
Action<Foo> myAction = new Action(new Foo().DoSomething).ToStaticMethod<Foo>();
Admittedly, it's not as nice as m => m.DoSomething(); but it does give you an Action<T> whose Method property actually references the DoSomething method directly.
Alternately, instead of an Action<T>, you could use an Expression<Action<T>> and get the MethodInfo from that. Note that the syntax looks just the same in this case:
Action<Foo> myAction = m => m.DoSomething();
Expression<Action<Foo>> myExpression = m => m.DoSomething();
But that is a tricky proposition since an arbitrary Expression<Action<T>> is not guaranteed to be as simple as just m => m.DoSomething().
None of previous answers (except #Marc Gravell♦ 's which has no user's code) seems to be compilable :)
So I would propose mine:
private static void CallDoSomething()
{
var f = new Foo();
Action myAction = f.DoSomething;
IEnumerable<StatusAttribute> statusAttributes = myAction.Method.GetCustomAttributes<StatusAttribute>(true);
}

Conditional typing in generic method

Consider the following (heavily simplified) code:
public T Function<T>() {
if (typeof(T) == typeof(string)) {
return (T) (object) "hello";
}
...
}
It's kind of absurd to first cast to object, then to T. But the compiler has no way of knowing that the previous test assured T is of type string.
What is the most elegant, idiomatic way of achieving this behavior in C# (which includes getting rid of the stupid typeof(T) == typeof(string), since T is string can't be used)?
Addendum: There is no return type variance in .net, so you can't make a function overload to type string (which, by the way, is just an example, but one reason why association end redefinition in polymorphism, e.g. UML, can't be done in c#). Obviously, the following would be great, but it doesn't work:
public T Function<T>() {
...
}
public string Function<string>() {
return "hello";
}
Concrete Example 1: Because there's been several attacks to the fact that a generic function that tests for specific types isn't generic, I'll try to provide a more complete example. Consider the Type-Square design pattern. Here follows a snippet:
public class Entity {
Dictionary<PropertyType, object> properties;
public T GetTypedProperty<T>(PropertyType p) {
var val = properties[p];
if (typeof(T) == typeof(string) {
(T) (object) p.ToString(this); // magic going here
}
return (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(val);
}
}
Concrete Example 2: Consider the Interpreter design pattern:
public class Expression {
public virtual object Execute() { }
}
public class StringExpression: Expression {
public override string Execute() { } // Error! Type variance not allowed...
}
Now let's use generics in Execute to allow the caller to force a return type:
public class Expression {
public virtual T Execute<T>() {
if(typeof(T) == typeof(string)) { // what happens when I want a string result from a non-string expression?
return (T) (object) do_some_magic_and_return_a_string();
} else if(typeof(T) == typeof(bool)) { // what about bools? any number != 0 should be True. Non-empty lists should be True. Not null should be True
return (T) (object) do_some_magic_and_return_a_bool();
}
}
}
public class StringExpression: Expressiong {
public override T Execute<T>() where T: string {
return (T) string_result;
}
}
If you're making these types of checks in a generic method, I'd rethink your design. The method is obviously not truly generic - if it were, you wouldn't need specific type checking...
Situations like this typically can be handled more cleanly by a redesign. One alternative is often to provide an overload of the appropriate type. Other design alternatives which avoid the type-specific behavior exist, as well, such as Richard Berg's suggestion of passing in a delegate.
using System;
using System.Collections.Generic;
using System.Linq;
namespace SimpleExamples
{
/// <summary>
/// Compiled but not run. Copypasta at your own risk!
/// </summary>
public class Tester
{
public static void Main(string[] args)
{
// Contrived example #1: pushing type-specific functionality up the call stack
var strResult = Example1.Calculate<string>("hello", s => "Could not calculate " + s);
var intResult = Example1.Calculate<int>(1234, i => -1);
// Contrived example #2: overriding default behavior with an alternative that's optimized for a certain type
var list1 = new List<int> { 1, 2, 3 };
var list2 = new int[] { 4, 5, 6 };
Example2<int>.DoSomething(list1, list2);
var list1H = new HashSet<int> { 1, 2, 3 };
Example2<int>.DoSomething<HashSet<int>>(list1H, list2, (l1, l2) => l1.UnionWith(l2));
}
}
public static class Example1
{
public static TParam Calculate<TParam>(TParam param, Func<TParam, TParam> errorMessage)
{
bool success;
var result = CalculateInternal<TParam>(param, out success);
if (success)
return result;
else
return errorMessage(param);
}
private static TParam CalculateInternal<TParam>(TParam param, out bool success)
{
throw new NotImplementedException();
}
}
public static class Example2<T>
{
public static void DoSomething(ICollection<T> list1, IEnumerable<T> list2)
{
Action<ICollection<T>, IEnumerable<T>> genericUnion = (l1, l2) =>
{
foreach (var item in l2)
{
l1.Add(item);
}
l1 = l1.Distinct().ToList();
};
DoSomething<ICollection<T>>(list1, list2, genericUnion);
}
public static void DoSomething<TList>(TList list1, IEnumerable<T> list2, Action<TList, IEnumerable<T>> specializedUnion)
where TList : ICollection<T>
{
/* stuff happens */
specializedUnion(list1, list2);
/* other stuff happens */
}
}
}
/// I confess I don't completely understand what your code was trying to do, here's my best shot
namespace TypeSquarePattern
{
public enum Property
{
A,
B,
C,
}
public class Entity
{
Dictionary<Property, object> properties;
Dictionary<Property, Type> propertyTypes;
public T GetTypedProperty<T>(Property p)
{
var val = properties[p];
var type = propertyTypes[p];
// invoke the cast operator [including user defined casts] between whatever val was stored as, and the appropriate type as
// determined by the domain model [represented here as a simple Dictionary; actual implementation is probably more complex]
val = Convert.ChangeType(val, type);
// now create a strongly-typed object that matches what the caller wanted
return (T)val;
}
}
}
/// Solving this one is a straightforward application of the deferred-execution patterns I demonstrated earlier
namespace InterpreterPattern
{
public class Expression<TResult>
{
protected TResult _value;
private Func<TResult, bool> _tester;
private TResult _fallback;
protected Expression(Func<TResult, bool> tester, TResult fallback)
{
_tester = tester;
_fallback = fallback;
}
public TResult Execute()
{
if (_tester(_value))
return _value;
else
return _fallback;
}
}
public class StringExpression : Expression<string>
{
public StringExpression()
: base(s => string.IsNullOrEmpty(s), "something else")
{ }
}
public class Tuple3Expression<T> : Expression<IList<T>>
{
public Tuple3Expression()
: base(t => t != null && t.Count == 3, new List<T> { default(T), default(T), default(T) })
{ }
}
}
Can you use as here?
T s = "hello" as T;
if(s != null)
return s;
I can't think of an "elegant" way to do this. As you say, the compiler can't know that the conditional has ensured that the type of T is string. As a result, it has to assume that, since there's no generalized way to convert from string to T, it's an error. object to T might succeed, so the compiler allows it.
I'm not sure I'd want an elegant way to express this. Although I can see where it'd be necessary to do explicit type checks like this in some situations, I think I'd want it to be cumbersome because it really is a bit of a hack. And I'd want it to stick out: "Hey! I'm doing something weird here!"
Ok, I took a run at it from several different angles and came up short. I would have to conclude that if your current implementation gets the job done you should take the win and move on. Short of some arcane emissions what you got is what you get.
But the compiler has no way of knowing
that the previous test assured T is of
type string.
Umm.... If I am not mistaken, generics is just code gen. The compiler generates a matching method for each distinct type found in the calling methods. So the compiler does know the type argument for the overload being called. Again; If I am not mistaken.
But overall, i think you are misusing the generic in this case, from what I can see, and as others have stated, there are more appropriate solutions..... which are unnamable unless you post code that completely specifies your requirements.
just my 2 pesos...

Categories

Resources