How would you do specialization in C#?
I'll pose a problem. You have a template type, you have no idea what it is. But you do know if it's derived from XYZ you want to call .alternativeFunc(). A great way is to call a specialized function or class and have normalCall return .normalFunc() while have the other specialization on any derived type of XYZ to call .alternativeFunc(). How would this be done in C#?
In C#, the closest to specialization is to use a more-specific overload; however, this is brittle, and doesn't cover every possible usage. For example:
void Foo<T>(T value) {Console.WriteLine("General method");}
void Foo(Bar value) {Console.WriteLine("Specialized method");}
Here, if the compiler knows the types at compile, it will pick the most specific:
Bar bar = new Bar();
Foo(bar); // uses the specialized method
However....
void Test<TSomething>(TSomething value) {
Foo(value);
}
will use Foo<T> even for TSomething=Bar, as this is burned in at compile-time.
One other approach is to use type-testing within a generic method - however, this is usually a poor idea, and isn't recommended.
Basically, C# just doesn't want you to work with specializations, except for polymorphism:
class SomeBase { public virtual void Foo() {...}}
class Bar : SomeBase { public override void Foo() {...}}
Here Bar.Foo will always resolve to the correct override.
Assuming you're talking about template specialization as it can be done with C++ templates - a feature like this isn't really available in C#. This is because C# generics aren't processed during the compilation and are more a feature of the runtime.
However, you can achieve similar effect using C# 3.0 extension methods. Here is an example that shows how to add extension method only for MyClass<int> type, which is just like template specialization. Note however, that you can't use this to hide default implementation of the method, because C# compiler always prefers standard methods to extension methods:
class MyClass<T> {
public int Foo { get { return 10; } }
}
static class MyClassSpecialization {
public static int Bar(this MyClass<int> cls) {
return cls.Foo + 20;
}
}
Now you can write this:
var cls = new MyClass<int>();
cls.Bar();
If you want to have a default case for the method that would be used when no specialization is provided, than I believe writing one generic Bar extension method should do the trick:
public static int Bar<T>(this MyClass<T> cls) {
return cls.Foo + 42;
}
I was searching for a pattern to simulate template specialization, too. There are some approaches which may work in some circumstances. However what about the case
static void Add<T>(T value1, T value2)
{
//add the 2 numeric values
}
It would be possible to choose the action using statements e.g. if (typeof(T) == typeof(int)). But there is a better way to simulate real template specialization with the overhead of a single virtual function call:
public interface IMath<T>
{
T Add(T value1, T value2);
}
public class Math<T> : IMath<T>
{
public static readonly IMath<T> P = Math.P as IMath<T> ?? new Math<T>();
//default implementation
T IMath<T>.Add(T value1, T value2)
{
throw new NotSupportedException();
}
}
class Math : IMath<int>, IMath<double>
{
public static Math P = new Math();
//specialized for int
int IMath<int>.Add(int value1, int value2)
{
return value1 + value2;
}
//specialized for double
double IMath<double>.Add(double value1, double value2)
{
return value1 + value2;
}
}
Now we can write, without having to know the type in advance:
static T Add<T>(T value1, T value2)
{
return Math<T>.P.Add(value1, value2);
}
private static void Main(string[] args)
{
var result1 = Add(1, 2);
var result2 = Add(1.5, 2.5);
return;
}
If the specialization should not only be called for the implemented types, but also derived types, one could use an In parameter for the interface. However, in this case the return types of the methods cannot be of the generic type T any more.
By adding an intermediate class and a dictionary, specialization is possible.
To specialize on T, we create an generic interface, having a method called (e.g.) Apply. For the specific classes that interface is implemented, defining the method Apply specific for that class. This intermediate class is called the traits class.
That traits class can be specified as a parameter in the call of the generic method, which then (of course) always takes the right implementation.
Instead of specifying it manually, the traits class can also be stored in a global IDictionary<System.Type, object>. It can then be looked up and voila, you have real specialization there.
If convenient you can expose it in an extension method.
class MyClass<T>
{
public string Foo() { return "MyClass"; }
}
interface BaseTraits<T>
{
string Apply(T cls);
}
class IntTraits : BaseTraits<MyClass<int>>
{
public string Apply(MyClass<int> cls)
{
return cls.Foo() + " i";
}
}
class DoubleTraits : BaseTraits<MyClass<double>>
{
public string Apply(MyClass<double> cls)
{
return cls.Foo() + " d";
}
}
// Somewhere in a (static) class:
public static IDictionary<Type, object> register;
register = new Dictionary<Type, object>();
register[typeof(MyClass<int>)] = new IntTraits();
register[typeof(MyClass<double>)] = new DoubleTraits();
public static string Bar<T>(this T obj)
{
BaseTraits<T> traits = register[typeof(T)] as BaseTraits<T>;
return traits.Apply(obj);
}
var cls1 = new MyClass<int>();
var cls2 = new MyClass<double>();
string id = cls1.Bar();
string dd = cls2.Bar();
See this link to my recent blog and the follow ups for an extensive description and samples.
I think there is a way to achieve it with .NET 4+ using dynamic resolution:
static class Converter<T>
{
public static string Convert(T data)
{
return Convert((dynamic)data);
}
private static string Convert(Int16 data) => $"Int16 {data}";
private static string Convert(UInt16 data) => $"UInt16 {data}";
private static string Convert(Int32 data) => $"Int32 {data}";
private static string Convert(UInt32 data) => $"UInt32 {data}";
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Converter<Int16>.Convert(-1));
Console.WriteLine(Converter<UInt16>.Convert(1));
Console.WriteLine(Converter<Int32>.Convert(-1));
Console.WriteLine(Converter<UInt32>.Convert(1));
}
}
Output:
Int16 -1
UInt16 1
Int32 -1
UInt32 1
Which shows that a different implementation is called for different types.
Some of the proposed answers are using runtime type info: inherently slower than compile-time bound method calls.
Compiler does not enforce specialization as well as it does in C++.
I would recommend looking at PostSharp for a way to inject code after the usual compiler is done to achieve an effect similar to C++.
A simpler, shorter and more readable version of what #LionAM proposed (about half of the code size), shown for lerp since this was my actual use case:
public interface ILerp<T> {
T Lerp( T a, T b, float t );
}
public class Lerp : ILerp<float>, ILerp<double> {
private static readonly Lerp instance = new();
public static T Lerp<T>( T a, T b, float t )
=> ( instance as ILerp<T> ?? throw new NotSupportedException() ).Lerp( a, b, t );
float ILerp<float>.Lerp( float a, float b, float t ) => Mathf.Lerp( a, b, t );
double ILerp<double>.Lerp( double a, double b, float t ) => Mathd.Lerp( a, b, t );
}
You can then just e.g.
Lerp.Lerp(a, b, t);
in any generic context, or provide the method as a grouped Lerp.lerp method reference matching T(T,T,float) signature.
If ClassCastException is good enough for you, you can of course just use
=> ( (ILerp<T>) instance ).Lerp( a, b, t );
to make the code even shorter/simpler.
If you just want to test if a type is derrived from XYZ, then you can use:
theunknownobject.GetType().IsAssignableFrom(typeof(XYZ));
If so, you can cast "theunknownobject" to XYZ and invoke alternativeFunc() like this:
XYZ xyzObject = (XYZ)theunknownobject;
xyzObject.alternativeFunc();
Hope this helps.
Related
Basically I want to use my own types instead of primitives like int/double, but still pass around these primitive values. Something like:
interface IInt {} // My interface to represent int. If I could fake so "int" implements this, all would work.
interface IPostNumber : IInt {} // Post number is an int. But int is not type safe enough for me.
void MyFunction(IPostNumber postNumber); // My function that should accept int/IPostNumber.
MyFunction(42); // This could also work with implicit conversion, but not allowed for interfaces:(
From ispiro's suggestion I found something that should cover everything.
So I declare my interfaces independent of underlying representation, e.g.
public interface IPostNumber{}
public interface IPostNumberFrom : IPostNumber{}
public interface IPostNumberTo : IPostNumber{}
These have full interface generality such as multiple inheritance. Then the data representation is done with generic classes with implicit conversion:
public class CInt<T>
{
public int value;
public static implicit operator int(CInt<T> d) => d.value;
public static implicit operator CInt<T>(int b) => new CInt<T>() { value = b };
}
Functions that accepts IPostNumber with int, is done as such:
private int TestPostNumberInt(CInt<IPostNumber> i) => i;
private int TestPostNumberFrom(CInt<IPostNumberFrom> i) => i;
CInt<IPostNumber> a = 4; // Works
Assert.Equal(1, TestPostNumberInt(1)); // Works
Assert.Equal(1, TestPostNumberFrom(a)); // Don't compile with IPostNumber into IPostNumberFrom
Now I can always declare CString<IPostNumber>, if some post numbers are represented with string. Or a function could accept the IPostNumber interface itself, if I make some class of it. Now one little issue is that if I want to pass CInt<IPostNumberFrom> to TestPostNumber, the method must be generic with T : IPostNumber, like this:
private int TestPostNumberInt<T>(CInt<T> i) where T : IPostNumber => i;
private int TestPostNumberIntFrom<T>(CInt<T> i) where T : IPostNumberFrom => i;
and then the generic type will not be detected while using implicit conversion (must cast). But we'll see if this is a big deal.
Also for later consideration: I will have class CJSON<T> : CString<T>. From what I see it works, though argubly CJSON could have different representations as well, like byte[] in some context. (But this is taking things far). So just need to think hard about representation vs. interfaces for my domain concepts.
I think what you might be looking for are implicit operators, but unfortunately I believe they're not supported for interfaces in the C# language specification. You can do this with subclasses if need be. Here's an example:
public class MyInt
{
int SomeValue;
public TestInt(int i)
{
SomeValue = i;
}
public static implicit operator MyInt(int i)
{
return new MyInt(i);
}
public static implicit operator int(MyInt myInt)
{
return myInt.SomeValue;
}
}
To assign using an implicit operator, you can do this:
MyInt n = 3;
int x = n;
See: implicit operator using interfaces
Is it this you're looking for?
public class IInt
{
public int TheInt;
public IInt(int theInt)
{
TheInt = theInt;
}
}
and then either use:
IInt i = new IInt(42);
MyFunction(i);
or define MyFunction for int and then use:
IInt i = new IInt(42);
MyFunction(i.TheInt);
Just one more idea:
public class IInt<T> where T : struct
{
public T TheInt;
public IInt(T theInt)
{
TheInt = theInt;
}
}
You can create an extension method but that method should be explicitly called.
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.
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.
I would like to differentiate between following cases:
A plain value type (e.g. int)
A nullable value type (e.g. int?)
A reference type (e.g. string) - optionally, I would not care if this mapped to (1) or (2) above
I have come up with the following code, which works fine for cases (1) and (2):
static void Foo<T>(T a) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
However, if I try to detect case (3) like this, it does not compile:
static void Foo<T>(T a) where T : class { } // 3
The error message is Type 'X' already defines a member called 'Foo' with the same parameter types. Well, somehow I cannot make a difference between where T : struct and where T : class.
If I remove the third function (3), the following code does not compile either:
int x = 1;
int? y = 2;
string z = "a";
Foo (x); // OK, calls (1)
Foo (y); // OK, calls (2)
Foo (z); // error: the type 'string' must be a non-nullable value type ...
How can I get Foo(z) to compile, mapping it to one of the above functions (or a third one with another constraint, which I have not thought of)?
Constraints are not part of the signature, but parameters are. And constraints in parameters are enforced during overload resolution.
So let's put the constraint in a parameter. It's ugly, but it works.
class RequireStruct<T> where T : struct { }
class RequireClass<T> where T : class { }
static void Foo<T>(T a, RequireStruct<T> ignore = null) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
static void Foo<T>(T a, RequireClass<T> ignore = null) where T : class { } // 3
(better six years late than never?)
You cannot differentiate the type of method to call based only on the constraints, unfortunately.
So you need to define a method in a different class or with a different name instead.
Further to your comment on Marnix's answer, you can achieve what you want by using a bit of reflection.
In the example below, the unconstrained Foo<T> method uses reflection to farm out calls to the appropriate constrained method - either FooWithStruct<T> or FooWithClass<T>. For performance reasons we'll create and cache a strongly-typed delegate rather than using plain reflection every time the Foo<T> method is called.
int x = 42;
MyClass.Foo(x); // displays "Non-Nullable Struct"
int? y = 123;
MyClass.Foo(y); // displays "Nullable Struct"
string z = "Test";
MyClass.Foo(z); // displays "Class"
// ...
public static class MyClass
{
public static void Foo<T>(T? a) where T : struct
{
Console.WriteLine("Nullable Struct");
}
public static void Foo<T>(T a)
{
Type t = typeof(T);
Delegate action;
if (!FooDelegateCache.TryGetValue(t, out action))
{
MethodInfo mi = t.IsValueType ? FooWithStructInfo : FooWithClassInfo;
action = Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(t));
FooDelegateCache.Add(t, action);
}
((Action<T>)action)(a);
}
private static void FooWithStruct<T>(T a) where T : struct
{
Console.WriteLine("Non-Nullable Struct");
}
private static void FooWithClass<T>(T a) where T : class
{
Console.WriteLine("Class");
}
private static readonly MethodInfo FooWithStructInfo = typeof(MyClass).GetMethod("FooWithStruct", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly MethodInfo FooWithClassInfo = typeof(MyClass).GetMethod("FooWithClass", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly Dictionary<Type, Delegate> FooDelegateCache = new Dictionary<Type, Delegate>();
}
(Note that this example is not threadsafe. If you require thread-safety then you'll either need to use some sort of locking around all access to the cache dictionary, or -- if you're able to target .NET4 -- use ConcurrentDictionary<K,V> instead.)
Drop the struct contraint on the first method. If you need to differentiate between value types and classes you can use the type of the argument to do so.
static void Foo( T? a ) where T : struct
{
// nullable stuff here
}
static void Foo( T a )
{
if( a is ValueType )
{
// ValueType stuff here
}
else
{
// class stuff
}
}
Amplifying my comment to LukeH, a useful pattern if one will need to use Reflection to invoke different actions based upon a type parameter (as distinct from the type of an object instance) is to create a private generic static class something like the following (this exact code is untested, but I've done this sort of thing before):
static class FooInvoker<T>
{
public Action<Foo> theAction = configureAction;
void ActionForOneKindOfThing<TT>(TT param) where TT:thatKindOfThing,T
{
...
}
void ActionForAnotherKindOfThing<TT>(TT param) where TT:thatOtherKindOfThing,T
{
...
}
void configureAction(T param)
{
... Determine which kind of thing T is, and set `theAction` to one of the
... above methods. Then end with ...
theAction(param);
}
}
Note that Reflection will throw an exception if one attempts to create a delegate for ActionForOneKindOfThing<TT>(TT param) when TT does not comply with that method's constraints. Because the system validated the type of TT when the delegate was created, one can safely invoke theAction without further type-checking. Note also that if outside code does:
FooInvoker<T>.theAction(param);
only the first call will require any Reflection. Subsequent calls will simply invoke the delegate directly.
Thankfully this kind of messing around is required less from C# version 7.3
See Whats new in C# 7.3 - Its not very explicit, but it now appears to use the 'where' arguments to some extent during overload resolution.
Overload resolution now has fewer ambiguous cases
Also see Selecting C# Version in your visual studio project
It will still see clashes with the following
Foo(x);
...
static void Foo<T>(T a) where T : class { } // 3
static void Foo<T>(T a) where T : struct { } // 3
But will correctly resolve
Foo(x);
...
static void Foo<T>(T a, bool b = false) where T : class { } // 3
static void Foo<T>(T a) where T : struct { } // 3
If you don't need generic parameters and just want to differentiate between these 3 cases at compile time you can use following code.
static void Foo(object a) { } // reference type
static void Foo<T>(T? a) where T : struct { } // nullable
static void Foo(ValueType a) { } // valuetype
With the latest compilers the RequireX approach can be done without introducing extra types and using only nullable ones (see at the sharplab.io):
using System;
using static Foos;
int x = 1;
int? y = 2;
string z = "a";
Foo(x); // OK, calls (1)
Foo(y); // OK, calls (2)
Foo(z); // OK, calls (3)
class Foos
{
public static void Foo<T>(T a, T? _ = null) where T : struct => Console.WriteLine(1); // 1
public static void Foo<T>(T? a) where T : struct => Console.WriteLine(2); // 2
public static void Foo<T>(T a, T? _ = null) where T : class => Console.WriteLine(3); // 3
}
Actually removing the 2nd parameter in the 3rd method also seems to work:
class Foos
{
public static void Foo<T>(T a, T? _ = null) where T : struct => Console.WriteLine(1); // 1
public static void Foo<T>(T? a) where T : struct => Console.WriteLine(2); // 2
public static void Foo<T>(T a) where T : class => Console.WriteLine(3); // 3
}
A variable of the type Int32 won't be threated as Int32 if we cast it to "Object" before passing to the overloaded methods below:
public static void MethodName(int a)
{
Console.WriteLine("int");
}
public static void MethodName(object a)
{
Console.ReadLine();
}
To handle it as an Int32 even if it is cast to "Object" can be achieved through reflection:
public static void MethodName(object a)
{
if(a.GetType() == typeof(int))
{
Console.WriteLine("int");
}
else
{
Console.ReadLine();
}
}
Is there another way to do that? Maybe using Generics?
Runtime overload resolution will not be available until C# 4.0, which has dynamic:
public class Bar
{
public void Foo(int x)
{
Console.WriteLine("int");
}
public void Foo(string x)
{
Console.WriteLine("string");
}
public void Foo(object x)
{
Console.WriteLine("dunno");
}
public void DynamicFoo(object x)
{
((dynamic)this).Foo(x);
}
}
object a = 5;
object b = "hi";
object c = 2.1;
Bar bar = new Bar();
bar.DynamicFoo(a);
bar.DynamicFoo(b);
bar.DynamicFoo(c);
Casting this to dynamic enables the dynamic overloading support, so the DynamicFoo wrapper method is able to call the best fitting Foo overload based on the runtime type of the argument.
public static void MethodName(object a)
{
if(a is int)
{
Console.WriteLine("int");
}
else
{
Console.WriteLine("object");
}
}
No, the specific overload of a method that is called is determined at compile-time, not at runtime, unless you're using reflection, thus if you've cast your int to an object, the object overload will be called. I don't believe there's any other way to do this, and generics won't do it for you either.
would this not work?
void MethodName<T>(object a){
T item = a as T;
// treat in the manner you require
}
MethodName<object>(1);
MethodName<Int32>(1);
Perhaps:
public static void MethodName(Type t)
{
Console.WriteLine(t.Name);
}
Then call it:
int a = 0;
string b = "";
object c = new object();
MethodName(a.GetType());
MethodName(b.GetType());
MethodName(c.GetType());
Or:
public static void MethodName<T>(T a)
{
Console.WriteLine(a.GetType().Name);
}
And finally:
public static void MethodName<T>()
{
Console.WriteLine(typeof(T).Name);
}
Update:
It comes down to the fact that the language must somehow be able to determine what type you will be dealing at compile time.
You're pretty much stuck with if/else constructs if you're looking to switch on types. The switch statement itself won't work due to polymorphism. If you're using non-primitive objects, than you can usually accomplish this sort of behavior either with polymorphism or interfaces, such that:
public static void MethodName(MyBaseObject obj)
{
Console.WriteLine(obj.MyVirtualFunctionCall());
}
dynamic overloading was an issue until .NET 3.5, but with .NET 4 its very feasible with few lines of code.
public void publish(dynamic queue)
{
publish(queue);
Console.WriteLine("dynamic queue publishing");
}
public void publish(ValidationQueue queue)
{
Console.WriteLine("Validation queue publishing");
}
how to call
foreach (var queue in _vodaQueueDAO.FetchAllReadyQueuesWithHighestPriority())
{
PublishingService.publish(queue);
}
I wrote an implementation for .NET 3.5 where you e.g. can do something like:
object a = 5;
OverloadResolver.Invoke(MethodName, a);
and it would use the int overload.
Works with compiled and cached Lambda expressions so the performance should be ok.
If anybody needs it, mail me, herzmeisterderwelten, who resides at gmail.com