How can I define a generic extension method - c#

I am trying to define an extension method that can return an object of a type defined by the call.
Desired Use: Cat acat = guy.GiveMeYourPet<Cat>();
Attempted implementation
I have no trouble defining generic methods like this:
public static T GiveMeYourPet<T>(Person a) { ... }
Cat acat = GiveMeYourPet<Cat>(guy);
or extension methods like this:
public static Cat GiveMeYourPetCat<P>(this P self) where P : Person, ... { ... }
Cat acat = guy.GiveMeYourPetCat();
But when I try to do what I really want:
public static T GiveMeYourPet<T, P>(this P self) where P : Person, ... { ... }
Cat acat = guy.GiveMeYourPet<Cat>();
The compiler expects GiveMeYourPet() to receive 2 type arguments (even though one is implicitly provided by calling the extension method on the object guy.
What can I do to make this work?
Note that I've also tried reversing the order in which the parameters are defined, but nothing changes:
public static T GiveMeYourPet<P, T>(this P self)
The following call also does not work, because you cannot have a method call in the type specifiation:
Cat acat = guy.GiveMeYourPet<guy.GetType(), Cat>();

The C# compiler type inference is not as sophisticated as you might hope. You have to explicitly specify both types in such a method:
void Main()
{
int i = 0;
bool b = i.GiveMeYourPet<bool, int>();
}
public static class MyExtensions
{
public static T GiveMeYourPet<T, P>(this P self)
{
return default(T);
}
}
If you want to avoid specifying both explicitly (and I wouldn't blame you), you might try to change your method to something like:
public static T GiveMeYourPet<T>(this IPetOwner self)
(with this interface, you shouldn't even need to know what the real type is; if you do, use as or is) Or even:
public static T GiveMeYourPet<T>(this object self)
(and use as or is)
If that's not an option, and the real type of guy (in your example) is not statically known (e.g. you just have him as an object), you'll probably have to use reflection, e.g.:
MethodInfo method = typeof(MyExtensions).GetMethod("GiveMeYourPet");
MethodInfo generic = method.MakeGenericMethod(typeof(Pet), guy.GetType());
generic.Invoke(guy, null);

If something like guy.GiveMeYour.Pet<Cat>(); would work you can build 2 levels similar to code:
public class GiveMeYourBuilder<P>
{
public P Me {get;set;}
public T Pet<T>() : where T: new()
{ return new T();}
}
public static PetExtensions
{
public GiveMeYourBuilder<P>(this P me)
{
return new GiveMeYourBuilder<P> { Me = me;}
}
}

You can't partially specify generic arguments, either they are all inferred or you have to specify them all. In this case, the closest you can get is probably to return an intermediate object which carries the generic Person type the extension method is called on, and define your Get methods on that:
public class GiveContext<T> where T : Person
{
public P MeYourPet<P>() where P : Pet
{
return default(P);
}
}
public static GiveContext<T> Give<T>(this T person) where T : Person
{
return new GiveContext<T>();
}
which you can use like:
var p = new Person();
Cat c = p.Give().MeYourPet<Cat>();

You can't do this, unfortunately. If the compiler can't figure them all out, you need to type out all the type arguments. The C# compiler isn't that smart. dynamic can help though:
public static T GiveMeYourPet<T>(this dynamic self)
{
//in here check that self meets your constraints using is, as, etc.
}

Related

How can I add an extension method to many classes?

I have about 1000 classes in which i need to count the number of properties of. I have the following code:
public static int NumberOfProperties()
{
Type type = typeof(C507);
return type.GetProperties().Count();
}
I could copy and paste this in to each class changing the typeof parameter but this seems a bit tedious.
Is there anyway to make an extensions method to do this by just doing var nop = C507.NumberOfProperties();?
Just to add to the answers suggesting an extension for object for completeness: you can also consider implementing an extension only for Type:
public static int GetPropertyCount(this Type t)
{
return t.GetProperties().Length;
}
and use it like this:
typeof(C507).GetPropertyCount();
The advantage is that you can get the number of properties directly from the type and do not have to create an instance first.
So you can write an extension method that uses object or one that uses type.
public static class ObjectExtensions
{
public static int GetNumberOfProperties(this object value)
{
return value.GetType().GetProperties().Count();
}
public static int GetNumberOfProperties(this Type value)
{
return value.GetProperties().Count();
}
}
Usage:
new C507().GetNumberOfProperties();
typeof(C507).GetNumberOfProperties();
However, you explicitly state two things:
I could copy and paste this in to each class changing the typeof
I have about 1000 classes
You'll likely not want to instantiate a 1000 classes or copy and paste typeof() 1000 times
In this case, you will want to read them all from the Assembly.
So something like:
typeof(SomeClass).Assembly.GetTypes().Select(x => new
{
x.Name,
PropertyCount = x.GetType().GetProperties().Count()
});
Where SomeClass is a class (doesn't matter which) where all the classes reside.
I just simply select them out into an anonymous object which contains the Types name and property count.
This:
typeof(SomeClass).Assembly
Is just a convience way to get the assembly. There are other ways.
Assembly.GetAssembly(typeof(Program)).GetTypes()
Assembly.GetCallingAssembly().GetTypes()
Assembly.Load("Some Assemble Ref").GetTypes()
You can do allsorts with the types that you find. If you select out the Type itself, you can instantiate it later using Activator.CreateInstance (if it has parameterless constuctor). You can also auto fill the properties with reflection as well.
It is impossible to have a static extension method as you imagine it. That being said, it would be possible to create a generic method in a helper class as follows.
public static int NumberOfProperties<T>()
{
Type type = typeof(T);
return type.GetProperties().Count();
}
Given a type SomeType it could be called as int n = NumberOfProperties<SomeType>().
You could make an extension method on object like this:
public static int PropertyCount(this object thing)
{
return thing.GetType().GetProperties().Count();
}
And use it on any object you like:
var x = "some string";
var numProps = x.PropertyCount();
If you want to have an extension method on object:
public static ObjectExtensions
{
public static int NumberOfProperties(this object value)
{
if (null == value)
throw new ArgumentNullException("value"); // or return 0
// Length: no need in Linq here
return value.GetType().GetProperties().Length;
}
}
...
C507 myObj = new C507();
// How many properties does myObj instance have?
int propCount = myObj.NumberOfProperties();
If you want to have an extesnion method on Type:
public static TypeExtensions
{
public static int NumberOfProperties(this Type value)
{
if (null == value)
throw new ArgumentNullException("value"); // or return 0
// Length: no need in Linq here
return value.GetProperties().Length;
}
}
...
// How many properties does C507 type have?
int propCount = typeof(C507).NumberOfProperties();
There are a couple of ways to do this that are variations of the same thing.
You can pass the Type as an argument to a method:
public static class Helper {
public static int NumberOfProperties(Type type)
{
return type.GetProperties().Count();
}
}
Which you would call like this:
// Imagine you have a class called MyClass
var result = Helper.NumberOfProperties(typeof(MyClass));
You use use the generic system in C# to make the syntax a little cleaner. That would look like this:
public static class Helper {
// Notice the argument was removed and
// the use of the "generic" syntax <T>
public static int NumberOfProperties<T>()
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
And you would call it like this:
var result = Helper.NumberOfProperties<MyClass>();
You could also use "Extensions" which allow you to call it as if it was a method that belonged to your classes.
public static class Helper {
// notice the `this` keyword before the parameter
// this is what tells C# that this is an extension method
public static int NumberOfProperties<T>(this T #this)
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
This will allow you to call the method like this:
var instance = new MyClass();
var result = instance.NumberOfProperties();
In this example I used the generic syntax so that it applies to any type of object. If you wanted to limit it to only objects that inherit from a specific interface or base class you would just change it from using the generic syntax to using the base class/interface. Like this:
public static class Helper {
// notice the type got changed from a generic <T>
// to specifying the exact class you want to "extend"
public static int NumberOfProperties(this MyBaseClass #this)
{
var type = typeof(T);
return type.GetProperties().Count();
}
}
As #rené-vogt mentioned you can also create the extension method so that it extends the type Type instead. See his answer in this thread: https://stackoverflow.com/a/38455233/984780
You can make a generic extension method which can apply to all types:
public static int PropertyCount<T>(this T obj)
{
return typeof(T).GetProperties().Length;
}
This will apply to all types including value types (I.E. structs) which applying to object will not. Thanks to piedar for pointing out my mistake here, applying to object does still add this extension method to value types.
If your classed can implement an interface, then you can extend that interface.
public interface IExtensible {
}
class C507 : IExtensible {
}
public static int NumberOfProperties(this IExtensible extensible)
{
Type type = extensible.GetType();
return type.GetProperties().Count();
}
That being said, having hundreds of (generated?) classes looks like a bad solution to begin with.

How to Write Generic Extension Method to Convert Type in C#

I am writing a static guard class/api to validate parameters sent to methods.
Code so far looks like:
public static class Guard
{
public static GuardArgument<T> Ensure<T>(T value, string argumentName)
{
return new GuardArgument<T>(value, argumentName);
}
public static T Value<T>(this GuardArgument<T> guardArgument)
{
return guardArgument.Value;
}
// Example extension method
public static GuardArgument<T> IsNotNull<T>(this GuardArgument<T> guardArgument, string errorMessage)
{
if (guardArgument.Value == null)
{
throw new ArgumentNullException(guardArgument.Name, errorMessage);
}
return guardArgument;
}
}
It can be used as so:
public void Test(IFoo foo) {
Guard.Ensure(foo, "foo").IsNotNull();
}
Circumstances now require that I need to cast to concrete types from a supplied interface. Don't ask why, I just need to!
I want to add an As extension method to GuardArgument to do this, something like:
public static GuardArgument<TOut> As<TOut, TIn>(this GuardArgument<TIn> guardArgument, Type type)
where TOut : class
{
// Check cast is OK, otherwise throw exception
return new GuardArgument<TOut>(guardArgument.Value as TOut, guardArgument.Name);
}
I don't much like the syntax though. I want to be able to use the class as follows:
Foo foo = Guard.Ensure(foo, "foo")
.As(typeof(Foo))
.IsNotNull()
.Value();
I'm not sure how to write the extension method to allow this syntax though. I realise I can use the existing fluent API as:
Foo foo = Guard.Ensure(foo as Foo, "foo")
.IsNotNull()
.Value();
but I don't like this from a readability perspective.
You can get this syntax:
Foo foo = Guard.Ensure(foo, "foo")
.As<Foo>()
.IsNotNull()
.Value();
The trick is to ditch the TIn type param. It's not used in the As() method and bloats the API when type inference can't be used due to TOut. To be able to do that without getting As() suggested on all types you have to implement a new, non-generic interface for your GuardArgument<> class:
interface IGuardArgument
{
object Value { get; }
strign Name { get; }
}
public class GuardArgument<T> : IGuardArgument
{
// Explicit implementation to hide this property from
// intellisense.
object IGuardArgument.Value { get { return Value; }
// Rest of class here, including public properties Value and Name.
}
Now you can write the As() method with only one generic param:
public static GuardArgument<TOut> As<TOut>(this IGuardArgument guardArgument)
where TOut : class
{
// Check cast is OK, otherwise throw exception
return new GuardArgument<TOut>(guardArgument.Value as TOut, guardArgument.Name);
}
Introduce an IGuardArgument interface which GuardArgument{T} implements. Then you can remove TIn from the As extension method and remove the Type parameter.
Signature:
public static GuardArgument<TOut> As(this IGuardArgument guardArgument);
Usage:
Guard.Ensure(foo, "foo").As<Foo>().IsNotNull()

Changing Type at Runtime with GenericTypeArgument

This is what I am trying to get
(IList<Foo>)listPropertyInfo.GetValue(item)
This is how I get Foo type
listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]
This is what I tried but couldn't make it successfully
Convert.ChangeType(listPropertyInfo.GetValue(item), IList<listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]>)
and also this;
((typeof(IList<>).MakeGenericType(listPropertyInfo.GetValue(item).GetType().GenericTypeArguments.Single())))(listPropertyInfo.GetValue(item))
this is method where I am trying to implement
public static void trigger(IList<T> result)
{
foreach (var item in result)
{
foreach (var listPropertyInfo in typeof(T).GetProperties().ToList().FindAll(x => x.PropertyType.Name == typeof(IList<>).Name))
{
trigger((IList<Foo>)listPropertyInfo.GetValue(item));
}
}
}
I solved like this;
IList targetList = (IList)listPropertyInfo.GetValue(item);
Type foo = targetList.GetType().GenericTypeArguments.Single();
Type unboundGenericType = typeof(READ<>);
Type boundGenericType = unboundGenericType.MakeGenericType(foo);
MethodInfo doSomethingMethod = boundGenericType.GetMethod("trigger");
object instance = Activator.CreateInstance(boundGenericType);
doSomethingMethod.Invoke(instance, new object[] { targetList, f, properties });
If you use IList notation, Foo must be defined at compile time, you can't use expression that evaluates at runtime for Foo.
After reading your comments and and the code i would argue you are trying to do it at the wrong spot.
Here an example of how you could do this
public class MyGeneric<T>
{
public static void trigger(IList<T> result)
{
// do generic stuff where
// you do not need to know T
}
}
// this class does only explicit Foo related stuff
public class MyNONEGeneric
{
public static void trigger(IList<Foo> list)
{
// do some
}
}
class Program
{
static void Main(string[] args)
{
PersistentGenericBag<Foo> magicBag = myMagic<Foo>();
// call your generic which do some general list related stuff
MyGeneric<Foo>.trigger(list);
// call your none generic which do some foo related stuff
MyNONEGeneric.trigger(list);
}
}
like you can see i did some sort of "separation of concerns" / "single responsibility principle" here.
Every thing does only "one" thing. so if you are in need to change something you will know exactly where.
Also if you are working in a Team you can tell Person A to do the MyGeneric<T> and Person B to do the MyNONEGeneric

Generic method multiple (OR) type constraint

Reading this, I learned it was possible to allow a method to accept parameters of multiple types by making it a generic method. In the example, the following code is used with a type constraint to ensure "U" is an IEnumerable<T>.
public T DoSomething<U, T>(U arg) where U : IEnumerable<T>
{
return arg.First();
}
I found some more code which allowed adding multiple type constraints, such as:
public void test<T>(string a, T arg) where T: ParentClass, ChildClass
{
//do something
}
However, this code appears to enforce that arg must be both a type of ParentClass and ChildClass. What I want to do is say that arg could be a type of ParentClass or ChildClass in the following manner:
public void test<T>(string a, T arg) where T: string OR Exception
{
//do something
}
Your help is appreciated as always!
That is not possible. You can, however, define overloads for specific types:
public void test(string a, string arg);
public void test(string a, Exception arg);
If those are part of a generic class, they will be preferred over the generic version of the method.
Botz answer is 100% correct, here's a short explanation:
When you are writing a method (generic or not) and declaring the types of the parameters that the method takes you are defining a contract:
If you give me an object that knows how to do the set of things that
Type T knows how to do I can deliver either 'a': a return value of the
type I declare, or 'b': some sort of behavior that uses that type.
If you try and give it more than one type at a time (by having an or) or try to get it to return a value that might be more than one type that contract gets fuzzy:
If you give me an object that knows how to jump rope or knows how to calculate pi
to the 15th digit I'll return either an object that can go fishing or maybe mix
concrete.
The problem is that when you get into the method you have no idea if they've given you an IJumpRope or a PiFactory. Furthermore, when you go ahead and use the method (assuming that you've gotten it to magically compile) you're not really sure if you have a Fisher or an AbstractConcreteMixer. Basically it makes the whole thing way more confusing.
The solution to your problem is one of two possiblities:
Define more than one method that defines each possible transformation, behavior, or whatever. That's Botz's answer. In the programming world this is referred to as Overloading the method.
Define a base class or interface that knows how to do all the things that you need for the method and have one method take just that type. This may involve wrapping up a string and Exception in a small class to define how you plan on mapping them to the implementation, but then everything is super clear and easy to read. I could come, four years from now and read your code and easily understand what's going on.
Which you choose depends on how complicated choice 1 and 2 would be and how extensible it needs to be.
So for your specific situation I'm going to imagine you're just pulling out a message or something from the exception:
public interface IHasMessage
{
string GetMessage();
}
public void test(string a, IHasMessage arg)
{
//Use message
}
Now all you need are methods that transform a string and an Exception to an IHasMessage. Very easy.
If ChildClass means it is derived from ParentClass, you may just write the following to accept both ParentClass and ChildClass;
public void test<T>(string a, T arg) where T: ParentClass
{
//do something
}
On the otherhand, if you want to use two different types with no inheritance relation between them, you should consider the types implementing the same interface;
public interface ICommonInterface
{
string SomeCommonProperty { get; set; }
}
public class AA : ICommonInterface
{
public string SomeCommonProperty
{
get;set;
}
}
public class BB : ICommonInterface
{
public string SomeCommonProperty
{
get;
set;
}
}
then you can write your generic function as;
public void Test<T>(string a, T arg) where T : ICommonInterface
{
//do something
}
As old as this question is I still get random upvotes on my explanation above. The explanation still stands perfectly fine as it is, but I'm going to answer a second time with a type that's served me well as a substitute for union types (the strongly-typed answer to the question that's not directly supported by C# as is).
using System;
using System.Diagnostics;
namespace Union {
[DebuggerDisplay("{currType}: {ToString()}")]
public struct Either<TP, TA> {
enum CurrType {
Neither = 0,
Primary,
Alternate,
}
private readonly CurrType currType;
private readonly TP primary;
private readonly TA alternate;
public bool IsNeither => currType == CurrType.Neither;
public bool IsPrimary => currType == CurrType.Primary;
public bool IsAlternate => currType == CurrType.Alternate;
public static implicit operator Either<TP, TA>(TP val) => new Either<TP, TA>(val);
public static implicit operator Either<TP, TA>(TA val) => new Either<TP, TA>(val);
public static implicit operator TP(Either<TP, TA> #this) => #this.Primary;
public static implicit operator TA(Either<TP, TA> #this) => #this.Alternate;
public override string ToString() {
string description = IsNeither ? "" :
$": {(IsPrimary ? typeof(TP).Name : typeof(TA).Name)}";
return $"{currType.ToString("")}{description}";
}
public Either(TP val) {
currType = CurrType.Primary;
primary = val;
alternate = default(TA);
}
public Either(TA val) {
currType = CurrType.Alternate;
alternate = val;
primary = default(TP);
}
public TP Primary {
get {
Validate(CurrType.Primary);
return primary;
}
}
public TA Alternate {
get {
Validate(CurrType.Alternate);
return alternate;
}
}
private void Validate(CurrType desiredType) {
if (desiredType != currType) {
throw new InvalidOperationException($"Attempting to get {desiredType} when {currType} is set");
}
}
}
}
The above class represents a type that can be either TP or TA. You can use it as such (the types refer back to my original answer):
// ...
public static Either<FishingBot, ConcreteMixer> DemoFunc(Either<JumpRope, PiCalculator> arg) {
if (arg.IsPrimary) {
return new FishingBot(arg.Primary);
}
return new ConcreteMixer(arg.Secondary);
}
// elsewhere:
var fishBotOrConcreteMixer = DemoFunc(new JumpRope());
var fishBotOrConcreteMixer = DemoFunc(new PiCalculator());
Important Notes:
You'll get runtime errors if you don't check IsPrimary first.
You can check any of IsNeither IsPrimary or IsAlternate.
You can access the value through Primary and Alternate
There are implicit converters between TP/TA and Either<TP, TA> to allow you to pass either the values or an Either anywhere where one is expected. If you do pass an Either where a TA or TP is expected, but the Either contains the wrong type of value you'll get a runtime error.
I typically use this where I want a method to return either a result or an error. It really cleans up that style code. I also very occasionally (rarely) use this as a replacement for method overloads. Realistically this is a very poor substitute for such an overload.

Is it possible to using Type Inference for the first parameter and specify another type

This is a simple contrived example, but hopefully will illustrate my query.
public class Test
{
public string Name = "test";
}
public static class Ext
{
public static Test ConvertToTest<T1>(this T1 source)
{
return new Test();
}
public static T2 Convert<T1,T2>(this T1 source) where T2 : new()
{
return new T2();
}
}
ConvertToTest only needs one Type, so the following compile
Ext.ConvertToTest<string>("hello");
"hello".ConvertToTest();
The last uses type-interfence and this means it also works with anonymous classes, eg
var anon = (new { Name = "test" }) ;
anon.ConvertToTest();
However this is hardcoded to always use the class Test, whereas I want to be able to specify the type as in the second method
I can write
Ext.Convert<string, Test>("hello");
and this compiles, because I know both types at compile time, but I can't use it with anonymous classes, and I can't find a way of using type-inference plus the extra Type
It would be nice if I could do something like
anon.Convert<,Test>() ;
and the compiler would know to use inference for the first type (which isn't specified) and use Test as the second type.
Is there any way around this issue?
You can't do what you're asking on a single method, but if you're clever and willing to define a couple of different classes you should be able to make syntax like this possible:
var test = Ext.Convert("hello").To<Test>();
Just make Convert be based on a single generic type, and have it return a generic type based on that:
public Converter<T> Convert<T>(T source)
{
return new Converter<T>(source);
}
Then add a method to the type it returns which serves as a basic wrapper for your original method:
public class Converter<T>
{
T _source;
internal Converter(T source)
{
_source = source;
}
public T2 To<T2>()
{
return Ext.Convert<T, T2>(_source);
}
}
There is a way to do what you want. You use a template pattern - it's a little bit of a kludge but it allows you to infer both types. It can also be use to infer anonymous types.
Here it is:
public static T2 Convert<T1,T2>(this T1 source, Func<T2> template)
where T2 : new()
{
return new T2();
}
You can call it like this:
var anon = (new { Name = "test" }) ;
anon.Convert(() => new Test());
Which isn't too far from your pseudo-code.

Categories

Resources