Disclaimer: the unit-test related info for this question is not really relevant - you can skip to "The Problem" if you're not familiar with this, but it helps set the context.
I have a class that I need to unit-test. It looks like this:
public class NumberParser {
public static void CheckByteRange(string str){...}
[...]
public static void CheckFloatRange(string str){...}
[...]
}
I want to use an NUnit parametrized unit-test to test all these methods. Here's the test method:
[TestCaseSource("CheckRange_Overflow_Inputs")]
public void CheckRange_Overflow(string value, Action<string> method)
{
Assert.Throws<Exception>(() => method(value));
}
The test uses TestCaseSourceAttribute to specify a field that contains a list of sets of arguments to the test method.
Now, NUnit expects a field called CheckRange_Overflow_Inputs, of type object[], that itself contains object[] elements, each of which contains values for the arguments to the test method.
The problem:
Ideally, I'd like to write the field like this:
private static readonly object[] CheckRange_Overflow_Inputs
= new object[]
{
new object[]{byte.MaxValue, NumberParser.CheckByteRange },
[...]
new object[]{float.MaxValue, NumberParser.CheckFloatRange },
[...]
};
But the compiler complains it can't cast a method group to an object.
That makes sense - NumberParser.CheckByteRange could be ambiguous, e.g. it could be overloaded.
But how can I get the compiler to allow me to save (as an object) the method called NumberParser.CheckByteRange that takes a string and returns void ?
What I tried (and failed succeeded):
[...]
new object[]{byte.MaxValue, (Action<string>)NumberParser.CheckByteRange },
[...]
If the method was static, then your attempt would have worked. It can't work simply as
(Action<string>)NumberParser.CheckByteRange
when CheckByteRange is an instance (non-static) method because you haven't told it which instance (this) to use. So either:
make CheckByteRange into a static method
tell it which instance to use, i.e. (Action<string>)someInstance.CheckByteRange
With them static, the following compiles fine for me:
private static readonly object[] CheckRange_Overflow_Inputs
= new object[]
{
new object[]{byte.MaxValue, (Action<string>) NumberParser.CheckByteRange },
new object[]{float.MaxValue, (Action<string>) NumberParser.CheckFloatRange },
};
Related
The question is somewhat related to this: How can I cast a delegate that takes a derived-type argument to a delegate with a base-type argument? but I have a dynamic situation.
So lets say I have two classes:
class Base
{ }
class Derived : Base
{ }
static class Workers
{
public static void DoSomething(Derived obj) { ... }
}
As you can see Workers.DoSomething is Action<Derived> and I want to cast it to Action<Base>. I know this is unsafe but my case is as follows: I keep a dictionary
Dictionary<Type, Action<Base>> actions;
and based on given objects obj.GetType() I retrieve one action and call it. And so I guarantee in my code that such action will be called with an appropriate type.
But those actions depend on the derived type obviously. Now the linked question suggests something like
actions[typeof(Derived)] = (obj) => Workers.DoSomething((Derived)obj);
This is ok in a situation when you know types at compile time. But in my case I retrieve them via reflection. So here's the setup
Type objType; // given
MethodInfo doSomethingMethod; // given, guaranteed to be Action<objType>
actions[objType] = // here what?
So far, surprisingly, the simplest solution I came up with is to create the method dynamically like follows:
Type objType; // given
MethodInfo doSomethingMethod; // given
var dynamicMethod = new DynamicMethod(
$"Dynamic{doSomethingMethod.Name}",
typeof(void),
new Type[] { typeof(Base) },
typeof(Base).Module
);
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Callvirt, doSomethingMethod, null);
il.Emit(OpCodes.Ret);
actions[objType] = (Action<Base>)dynamicMethod
.CreateDelegate(typeof(Action<Base>));
And so I force the call at CIL level. My real code is slightly more complicated since those actions accept two parameters. But that's just noise.
This works (and there's no cast as a bonus). But it looks kind of... I don't know, unsafe. And probably hard to maintain. Is there a better way to solve my problem?
Note: I want to avoid doSomethingMethod.Invoke due to its significant overhead.
Note 2: I have no control over those classes and actions. I can only inspect them.
You seem aware that you are turning the rules of covariance and contravariance upside-down, nevertheless here's something fairly tidy that may work for the situation you describe (you can also check that (b as Derived) != null just to be sure):
class Base { }
class Derived : Base { }
static class Workers
{
public static void DoSomething(Derived obj) { Console.WriteLine("Test"); }
}
class Program
{
static Dictionary<Type, Action<Base>> actions;
// *** Note use of dummy to avoid having to know T at compile time and T : Base constraint
// (compiler can't infer T from Action<T> alone, this way runtime works out T from given object instance)...
static void AddAction<T>(T dummy, Action<T> a) where T : Base
{
actions.Add(typeof(T), b => a(b as T));
}
static void Main(string[] args)
{
actions = new Dictionary<Type, Action<Base>>();
var o = new Derived(); // the object you get "from elsewhere"
AddAction(o, Workers.DoSomething);
actions[o.GetType()](o);
Console.ReadKey();
}
}
Hope this is useful. (Very curious about the "Why?" though ;-)
I can't claim this as my idea, but found it here: https://stackoverflow.com/a/32702091/1848953 while researching your question.
First:
private static Action<object> ConvertDelegateToAction<T>(Delegate d) { return obj => ((Action<T>)d)((T)obj); }
private static readonly MethodInfo CastMethodInfo = typeof(Program).GetMethod(nameof(ConvertDelegateToAction), BindingFlags.Static | BindingFlags.NonPublic);
used:
public static Action<object> GetActionT(Type t, Delegate d) { return (Action<object>)CastMethodInfo.MakeGenericMethod(t).Invoke(null, new object[] { d }); }
Quite tidy I think. You GetType() at runtime and use Invoke() but only to get the Action<object> up-front. (Instead of a base class, I used an empty interface. Seemed to work fine.)
Let us know if this gives satisfaction.
I am loading a dll using loadfrom and iterating thru the methods to find ones that match a signature. When I find it I want to assign it as a delegate so I can call it later. This is what I am doing...
foreach (MethodInfo method in methodInfos)
{
if (method.GetParameters().Length == 2)
{
ParameterInfo[] parameters = method.GetParameters();
if (parameters[0].ParameterType.Name == "Command"
&& parameters[1].ParameterType.Name == "ExposedVariables")
{
aoc.methodinfo = method;
Command.delCmdMethod del = (Command.delCmdMethod)
Delegate.CreateDelegate(typeof(Command.delCmdMethod)
, null
, method);
}
}
}
Problem is - the delegate assignment does not work. I get an error binding to target method.
I read on the web that the the 2nd parameter could be the issue if the method is not static. My method is NOT static.
Any ideas?
Although Miky Dinescu's answer might be helpful, it is only partially correct. There does exist an overload for Delegate.CreateDelegate which will most likely help you.
First off, Miky is right that you have to pass the instance as the second parameter, but this is only the case if you want to create what is called a closed delegate. This means an instance is bound to the delegate along with the method. In practice this means when calling the delegate, it will always operate on the same instance.
From your question, it looks like that isn't what you are trying to achieve. If you want to be able to pass the instance along when calling the delegate, you have to use the CreateDelegate( Type type, MethodInfo method ) overload. This allows you to create what is called an open instance delegate.
Since you'll have to pass the instance along when calling the method, this means there is an extra parameter required in your delegate type. The first parameter of your delegate type will need to correspond to the type of the class in which the method is contained.
Example:
MethodInfo toUpperMethod
= typeof( string ).GetMethod( "ToUpper", new Type[] { } );
Func<string, string> toUpper
= (Func<string, string>)Delegate.CreateDelegate(
typeof( Func<string, string> ), toUpperMethod );
string upper = toUpper( "test" ); // Will result in "TEST".
Since - just like you - I found these overloads to be unclear, I created two helper functions to clearly separate creating a 'normal' delegate or an open instance delegate. This code, along with a more thorough discussion can be found in my blog post.
If the method is not static then you need to pass in a reference to an instance of the class who's method you are going to be invoking using the delegate.
If you don't know which instance you will be using at the time when you are attempting to create the delegate you will need to store the type and method information for later and then create the Delegate after you have the instance of the class.
EDIT
To answer your comment, the object that you need to pass is an object of the type that contains the method your are trying to bind your delegate to. So based on your code sample it's not the Command object but an object of the class from the DLL.
So, let's say that you have this .NET assembly DLL: myassembly.dll. The assembly contains the following class:
namespace MyNamespace
{
public class SomeClass
{
public SomeClass()
{
}
public void Method1(object Command, object ExposedVariables)
{
}
public void Method2(object Command, object ExposedVariables)
{
}
}
You would need to create an instance of the class SomeClass before you could create delegates bound to Method1 or Method2 of that class. So, the code which creates the delegate should look like this:
// assuming that method info is a MethodInfo contains information about the method
// that you want to create the delegate for, create an instance of the class which
// contains the method..
object classInstance = Activator.CreateInstance(methodInfo.DeclaringType);
// and then create the delegate passing in the class instance
Delegate.CreateDelegate(typeof(Command.delCmdMethod), classInstance, methodInfo);
I would like to overload a generic list's Add method so I can use collection initializations like:
var x = new List<Tuple<string>> { { "1", "2" }, { "1", "2" } };
(Where Tuple is a simple custom implementation of a binary tuple.)
However, I created an extension method, put a using directive in the cs file, and still get the "No overload for method 'Add' takes 2 arguments"-error.
Is it not possible to do (with an extension method)?
Extension method code:
namespace ExtensionMethods {
public static class Extensions{
public static void Add<T>(this List<Tuple<T>> self, T value1, T value2) {
self.Add(new Tuple<T> { value1, value2 });
}
}
}
It is not possible via extension methods. In order to make this syntax working you have to create your own collection class which will have void Add(T value1, T value2) signature.
P.S.: What you've done is not overload and there is no way to overload anything in existing class.
UPDATE: Looks like my first sentence should be: "It is not possible via extension methods in C#"
In C# 6.0[0] Microsoft allows the use of extensions methods in collection initializers. hurray :)
And since this isn't a .NET Framework or CLR change, but a compiler change, this feature can be used with .NET 4.0.
So the following is now valid C# code. (Tested in Visual Studio 2015 RC)
class Program
{
static void Main(string[] args)
{
var x = new List<Tuple<string,string>> { { "1", "2" }, { "1", "2" } };
}
}
public static class Extensions
{
public static void Add<T1,T2>(this List<Tuple<T1,T2>> self, T1 value1, T2 value2)
{
self.Add(Tuple.Create( value1, value2 ));
}
}
C# 6 Features [0]
You cannot implement constructors using extension methods.Extension method is nothing but a static method which takes in an instance of an object. Hence you need to have an instance first to be able to pass to it.
But you can just use AddRange() of the List to initialise your list.
Extension methods can't overload any method defined on their target type simply because they are not members of the target type. Extension methods do not ADD anything to their target types. They are just compiler magic that allow them to be called as if they were methods defined on their target type. In reality, they are defined in a separate static type, hence they can't overload any method on their target type.
Behind the scenes, the compiler replaces any calls to your extension method with a call to Extensions.
It looks like you are trying to make C# behave like Ruby and initialize an array of objects by passing a set of values, or at least imitate the behavior of dictionary initialization.
Unfortunately you can't do that without actually overloading List<>.
Collection initialization is just another bit of compiler magic that tries to find an Add method with as many arguments as there are items in the argument list. If it were otherwise you could define a conversion operator to convert a list to your Tuple type.
Why don't you just use the built-in object initializers? You'll just have to write a bit more code
I am working on rewriting my fluent interface for my IoC class library, and when I refactored some code in order to share some common functionality through a base class, I hit upon a snag.
Note: This is something I want to do, not something I have to do. If I have to make do with a different syntax, I will, but if anyone has an idea on how to make my code compile the way I want it, it would be most welcome.
I want some extension methods to be available for a specific base-class, and these methods should be generic, with one generic type, related to an argument to the method, but the methods should also return a specific type related to the particular descendant they're invoked upon.
Better with a code example than the above description methinks.
Here's a simple and complete example of what doesn't work:
using System;
namespace ConsoleApplication16
{
public class ParameterizedRegistrationBase { }
public class ConcreteTypeRegistration : ParameterizedRegistrationBase
{
public void SomethingConcrete() { }
}
public class DelegateRegistration : ParameterizedRegistrationBase
{
public void SomethingDelegated() { }
}
public static class Extensions
{
public static ParameterizedRegistrationBase Parameter<T>(
this ParameterizedRegistrationBase p, string name, T value)
{
return p;
}
}
class Program
{
static void Main(string[] args)
{
ConcreteTypeRegistration ct = new ConcreteTypeRegistration();
ct
.Parameter<int>("age", 20)
.SomethingConcrete(); // <-- this is not available
DelegateRegistration del = new DelegateRegistration();
del
.Parameter<int>("age", 20)
.SomethingDelegated(); // <-- neither is this
}
}
}
If you compile this, you'll get:
'ConsoleApplication16.ParameterizedRegistrationBase' does not contain a definition for 'SomethingConcrete' and no extension method 'SomethingConcrete'...
'ConsoleApplication16.ParameterizedRegistrationBase' does not contain a definition for 'SomethingDelegated' and no extension method 'SomethingDelegated'...
What I want is for the extension method (Parameter<T>) to be able to be invoked on both ConcreteTypeRegistration and DelegateRegistration, and in both cases the return type should match the type the extension was invoked on.
The problem is as follows:
I would like to write:
ct.Parameter<string>("name", "Lasse")
^------^
notice only one generic argument
but also that Parameter<T> returns an object of the same type it was invoked on, which means:
ct.Parameter<string>("name", "Lasse").SomethingConcrete();
^ ^-------+-------^
| |
+---------------------------------------------+
.SomethingConcrete comes from the object in "ct"
which in this case is of type ConcreteTypeRegistration
Is there any way I can trick the compiler into making this leap for me?
If I add two generic type arguments to the Parameter method, type inference forces me to either provide both, or none, which means this:
public static TReg Parameter<TReg, T>(
this TReg p, string name, T value)
where TReg : ParameterizedRegistrationBase
gives me this:
Using the generic method 'ConsoleApplication16.Extensions.Parameter<TReg,T>(TReg, string, T)' requires 2 type arguments
Using the generic method 'ConsoleApplication16.Extensions.Parameter<TReg,T>(TReg, string, T)' requires 2 type arguments
Which is just as bad.
I can easily restructure the classes, or even make the methods non-extension-methods by introducing them into the hierarchy, but my question is if I can avoid having to duplicate the methods for the two descendants, and in some way declare them only once, for the base class.
Let me rephrase that. Is there a way to change the classes in the first code example above, so that the syntax in the Main-method can be kept, without duplicating the methods in question?
The code will have to be compatible with both C# 3.0 and 4.0.
Edit: The reason I'd rather not leave both generic type arguments to inference is that for some services, I want to specify a parameter value for a constructor parameter that is of one type, but pass in a value that is a descendant. For the moment, matching of specified argument values and the correct constructor to call is done using both the name and the type of the argument.
Let me give an example:
ServiceContainerBuilder.Register<ISomeService>(r => r
.From(f => f.ConcreteType<FileService>(ct => ct
.Parameter<Stream>("source", new FileStream(...)))));
^--+---^ ^---+----^
| |
| +- has to be a descendant of Stream
|
+- has to match constructor of FileService
If I leave both to type inference, the parameter type will be FileStream, not Stream.
I wanted to create an extension method that could enumerate over a list of things, and return a list of those things that were of a certain type. It would look like this:
listOfFruits.ThatAre<Banana>().Where(banana => banana.Peel != Color.Black) ...
Sadly, this is not possible. The proposed signature for this extension method would have looked like:
public static IEnumerable<TResult> ThatAre<TSource, TResult>
(this IEnumerable<TSource> source) where TResult : TSource
... and the call to ThatAre<> fails because both type arguments need to be specified, even though TSource may be inferred from the usage.
Following the advice in other answers, I created two functions: one which captures the source, and another which allows callers to express the result:
public static ThatAreWrapper<TSource> That<TSource>
(this IEnumerable<TSource> source)
{
return new ThatAreWrapper<TSource>(source);
}
public class ThatAreWrapper<TSource>
{
private readonly IEnumerable<TSource> SourceCollection;
public ThatAreWrapper(IEnumerable<TSource> source)
{
SourceCollection = source;
}
public IEnumerable<TResult> Are<TResult>() where TResult : TSource
{
foreach (var sourceItem in SourceCollection)
if (sourceItem is TResult) yield return (TResult)sourceItem;
}
}
}
This results in the following calling code:
listOfFruits.That().Are<Banana>().Where(banana => banana.Peel != Color.Black) ...
... which isn't bad.
Notice that because of the generic type constraints, the following code:
listOfFruits.That().Are<Truck>().Where(truck => truck.Horn.IsBroken) ...
will fail to compile at the Are() step, since Trucks are not Fruits. This beats the provided .OfType<> function:
listOfFruits.OfType<Truck>().Where(truck => truck.Horn.IsBroken) ...
This compiles, but always yields zero results and indeed doesn't make any sense to try. It's much nicer to let the compiler help you spot these things.
If you have only two specific types of registration (which seems to be the case in your question), you could simply implement two extension methods:
public static DelegateRegistration Parameter<T>(
this DelegateRegistration p, string name, T value);
public static ConcreteTypeRegistration Parameter<T>(
this ConcreteTypeRegistration p, string name, T value);
Then you wouldn't need to specify the type argument, so the type inference would work in the example you mentioned. Note that you can implement both of the extension methods just by delegation to a single generic extension method with two type parameters (the one in your question).
In general, C# doesn't support anything like o.Foo<int, ?>(..) to infer only the second type parameter (it would be nice feature - F# has it and it's quite useful :-)). You could probably implement a workaround that would allow you to write this (basically, by separating the call into two method calls, to get two places where the type inferrence can be applied):
FooTrick<int>().Apply(); // where Apply is a generic method
Here is a pseudo-code to demonstrate the structure:
// in the original object
FooImmediateWrapper<T> FooTrick<T>() {
return new FooImmediateWrapper<T> { InvokeOn = this; }
}
// in the FooImmediateWrapper<T> class
(...) Apply<R>(arguments) {
this.InvokeOn.Foo<T, R>(arguments);
}
Why don't you specify zero type parameters? Both can be inferred in your sample. If this is not an acceptable solution for you, I'm frequently encountering this problem too and there's no easy way to solve the problem "infer only one type parameter". So I'll go with the duplicate methods.
What about the following:
Use the definition you provide:
public static TReg Parameter<TReg, T>(
this TReg p, string name, T value)
where TReg : ParameterizedRegistrationBase
Then cast the parameter so the inference engine gets the right type:
ServiceContainerBuilder.Register<ISomeService>(r => r
.From(f => f.ConcreteType<FileService>(ct => ct
.Parameter("source", (Stream)new FileStream(...)))));
I think you need to split the two type parameters between two different expressions; make the explicit one be part of the type of a parameter to the extension method, so inference can then pick it up.
Suppose you declared a wrapper class:
public class TypedValue<TValue>
{
public TypedValue(TValue value)
{
Value = value;
}
public TValue Value { get; private set; }
}
Then your extension method as:
public static class Extensions
{
public static TReg Parameter<TValue, TReg>(
this TReg p, string name, TypedValue<TValue> value)
where TReg : ParameterizedRegistrationBase
{
// can get at value.Value
return p;
}
}
Plus a simpler overload (the above could in fact call this one):
public static class Extensions
{
public static TReg Parameter<TValue, TReg>(
this TReg p, string name, TValue value)
where TReg : ParameterizedRegistrationBase
{
return p;
}
}
Now in the simple case where you are happy to infer the parameter value type:
ct.Parameter("name", "Lasse")
But in the case where you need to explicitly state the type, you can do so:
ct.Parameter("list", new TypedValue<IEnumerable<int>>(new List<int>()))
Looks ugly, but hopefully rarer than the simple fully-inferred kind.
Note that you could just have the no-wrapper overload and write:
ct.Parameter("list", (IEnumerable<int>)(new List<int>()))
But that of course has the disadvantage of failing at runtime if you get something wrong. Unfortunately away from my C# compiler right now, so apologies if this is way off.
I would used the solution:
public class JsonDictionary
{
public static readonly Key<int> Foo = new Key<int> { Name = "FOO" };
public static readonly Key<string> Bar = new Key<string> { Name = "BAR" };
IDictionary<string, object> _data;
public JsonDictionary()
{
_data = new Dictionary<string, object>();
}
public void Set<T>(Key<T> key, T obj)
{
_data[key.Name] = obj;
}
public T Get<T>(Key<T> key)
{
return (T)_data[key.Name];
}
public class Key<T>
{
public string Name { get; init; }
}
}
See:
C#: Exposing type safe API over heterogeneous dictionary
Consider the following class
public class PlanetKrypton
{
public static void CallSuperManforHelp(string helpMessage, params object[] kryptonParams)
{
Console.WriteLine(String.Format(helpMessage,kryptonParams));
}
public static void CallSuperManforHelp(string helpMessage ,string sender,string senderZipCode)
{
Console.WriteLine("{0} from {1}. I am {2}", helpMessage, sender, senderZipCode);
}
}
public class ConsoleMan
{
public static void Main(string[] args)
{
string helpMessage = "I have a flat tire";
string sender = "Jerry";
int wrongZipType = 12345;
PlanetKrypton.CallSuperManforHelp(helpMessage, sender, wrongZipType);
PlanetKrypton.CallSuperManforHelp(helpMessage);
}
}
Now, if I have a more strongly typed method signature in the first method, I would have gotten a compile time error for both these method calls.
Are there any "best practices" for using params in method signature ?
Edit:Am making this a community wiki
I rarely see a need for it, myself.
If my function might need a collection of items, I make it take exactly that: ICollection<> or IEnumerable<>, potentially with an overload that takes a single T for that special case.
If the function is more utilitarian in nature (for example, I have a generic multi-field HashCode generating function), where params might seem to fit, I will still provide quite a few overloads for specific cases like 1 arg, 2 args, 3 args ... sometimes to 5 args or 10 args. Then I will add a catch-all with params. I do this because of the array object creation implicit with params.
I would avoid using params[] object. What I would do is create a class that encapsulates the three strings in your second overload:
public class HelpStuff
{
public string Message{get;set;}
public string Help{get;set;}
public string ZipCode{get;set;}
}
Then have two overloads like this:
public static void CallSuperManforHelp(string helpMessage, params string[] kryptonParams)
{
//do work
}
public static void CallSuperManforHelp(HelpStuff helpStuff)
{
//do work
}
Well, the obvious thing is that compile time errors are better than runtime errors. However, a flexible, usable API sometimes has to take precedence. I'd say in general you should only use arrays of Object, which lack compile time type safety and are sometimes inefficient, if you're sure there's no more static way to accomplish what you want.
If you have this method:
public static void CallSuperManforHelp(string helpMessage, params object[] kryptonParams) { ... }
you can cool it with these code:
CallSuperManforHelp("please help");
CallSuperManforHelp("please help", (object[])null);
These calling are equivalent. So if you overloading the "CallSuperManforHelp", you should think about calling convenction of these methods.
It's rarely needed, but useful at times - so I wouldn't say it's a best practice to avoid it. Just try to avoid ambiguity.
String.Format is of course the canonical example, and most cases where I use params, it's to pass to String.Format (e.g. a logging method).
Another example from the framework is DataRowCollection.Add: it's useful to be able to add field values without building an object array first:
DataTable myDataTable;
...
for(...)
{
myDataTable.Rows.Add(col1Value, col2Value, col3Value);
}
I wouldn't mix params/regular overloads in that way - I'd only generally use params to add an override that takes additional (unknown at compile time) parameters.
e.g. A normal method, and then one that takes an additional params:
public static void CallSuperManforHelp(string helpMessage);
public static void CallSuperManforHelp(string helpMessage, params object[] kryptonParams);
This eliminates the ambiguity between the overloads.
If you want the two methods you have defined, then you could simply give them different names to avoid any ambiguity and clarify their usage:
public static void CallSuperManforHelpFormatted(string helpMessage, params object[] kryptonParams)
public static void CallSuperManforHelp(string helpMessage ,string sender,string senderZipCode)