declare value tuples in generic method signature - c#

I want to create methods which are able to convert lists to tuples (or a struct) by matching types.
I would also need to create overloads for several tuple component counts so I could for example call:
var t1 = GetAsTuple<(HealthComponent)>(components);
var t2 = GetAsTuple<(PositionComponent, ModelComponent)>(components);
var t3 = GetAsTuple<(Texture, ModelComponent, PositionComponent)>(components);
Since I have lots of combinations of these I call them component-tuples I want to avoind lots of boilerplate code and want a generic mechanism to fill these tuples.
This is what I tried, obviously it does not compile:
public T GetAsTuple<T>(Component[] components)
where T : ValueTuple<x, y>, new()
where x : Component
where y : Component
{
var t = new T();
t.Item1 = components.OfType<x>().Single();
t.Item2 = components.OfType<y>().Single();
return t;
}
Is it possible what I am trying to do or is there another way to get the desired behavior.
I know that I could reach what Iam trying to do with reflection, but this is too slow for the context (game development).

A solution to get these Tuples as you've specified would actually require many, very similar methods. If you look into the .Net source code you'll see that this is actually how the Tuple.Create method works:
var t1 = GetAsTuple<HealthComponent>(components);
var t2 = GetAsTuple<PositionComponent, ModelComponent>(components);
var t3 = GetAsTuple<Texture, ModelComponent, PositionComponent>(components);
public Tuple<T1> GetAsTuple<T1>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>());
public Tuple<T1, T2> GetAsTuple<T1, T2>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>(),
components.GetComponent<T2>());
public Tuple<T1, T2, T3> GetAsTuple<T1, T2, T3>(Component[] components)
=> Tuple.Create(components.GetComponent<T1>(),
components.GetComponent<T3>(),
components.GetComponent<T2>());
... etc ...
// I would still use this extension
public static class ComponentExtensions
{
public static T GetComponent<T>(this Component[] components)
{
return components.OfType<T>().Single(); // note this will throw if 0 or more than 1 are in the array.
}
}

For now I will stick with a reflection based solution.
When I have the time I will implement a T4-template which generates the method overloads for me.

You could have a much simpler method to get the specific component:
public static class ComponentExtensions
{
public static T GetComponent<T>(this Component[] components)
{
return components.OfType<T>().Single(); // note this will throw if 0 or more than 1 are in the array.
}
}
Then I expect you'd have classes that deal with specific things and need certain components:
public class SomethingDoer
{
private readonly PositionComponent _position;
private readonly ModelComponent _model;
public SomethingDoer(Component[] components)
{
_position = components.GetComponent<PositionComponent>();
_model = components.GetComponent<ModelComponent>();
}
public void DoSomething()
{
...
}

Related

Generic implementation where type could be one of two [duplicate]

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.

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...

Variable number of results from a function

I have code similar to the following in many places:
var dbParams = db.ReadParams(memberID, product, GetSubscriptionFields());
Debug.Assert(dbParams.Count == 4);
_memberCode = dbParams[0];
_password = dbParams[1];
_userName = dbParams[2];
_reasonCode = dbParams[3];
ReadParams() returns an array of strings, the number of strings depending on the GetSubscriptionFields() function. I could use dbParams[] directly in my code, but I find it more helpful to give meaningful names to each of the values in the array. Is there a way I can get all the results directly, without going through the array?
I am looking for something like:
db.ReadParams(memberID, product, out _memberCode, out _password, out _userName, out _reasonCode);
or
Tuple<_memberCode, _password, _userName, _reasonCode> = db.ReadParams(memberID, product);
Of course, it has to be legal C# code :)
You are writing code in a highly object oriented language, so why don't you use objects?
Member m = db.ReadParams(memberID, product, GetSubscriptionFields());
and in your code you use
m.memberCode
m.password
m.username
m.reasonCode
Of course you don't have to make the values publicly accessible, you can make them only accessible via setter/getter methods, and by only having getters, you can avoid them from being altered after object creation.
Of course different calls to db.ReadParams should return different objects, e.g. you can create an abstract base class and inherit all possible results from db.ReadParams of it. Therefor you may have to encapsulate db.ReadParams into another method that finds out the right type of object to create:
ReadParamsResult rpr = myDb.ReadParamsAsObject(memberID, product, GetSubscriptionFields());
// Verify that the expected result object has been returned
Debug.Assert(rpr is Member);
// Downcast
Member m = (Member)rpr;
Why not use constants instead?
Then in your code you could have
dbParams[MEMBER_CODE]
dbParams[PASSWORD]
dbParams[USERNAME]
dbParams[REASON_CODE]
which meets your goal of meaningful names without changing the way the method works.
I think your Tuple idea is pretty good. You could define it like this:
public class Tuple<T1, T2, T3, T4>
{
public T1 Field1 { get; set; }
public T2 Field2 { get; set; }
public T3 Field3 { get; set; }
public T4 Field4 { get; set; }
}
You would probably want to define a few of those, with two and three properties. Unfortunately it doesn't help you naming the properties of the class. There really is no way to do that (at least not until C# 4.0, when you could use dynamic typing with an anonymous type.
Not really; since the number of arguments isn't fixed, there isn't really a better way of doing it. The problem with regular tuples is that you are still working positionally - just with ".Value0" instead of "[0]". And anonymous types can't be directly exposed in an API.
Of course, you could subsequently wrap the values in your own class with properties, and just do a projection:
return new Foo {MemberCode = arr[0], ...}
(where Foo is your class that represents whatever this result is, with named, typed properties)
Alternatively you could throw them into a dictionary, but this doesn't help the caller any more than an array does.
The only other option is something really grungy like accepting a params array of Action<string> that you use to assign each. I'll elaborate on the last just for fun - I don't suggest you do this:
static void Main()
{
string name = "";
int value = 0;
Foo("whatever",
x => { name = x; },
x => { value = int.Parse(x); });
}
// yucky; wash eyes after reading...
static void Foo(string query, params Action<string>[] actions)
{
string[] results = Bar(query); // the actual query
int len = actions.Length < results.Length ? actions.Length : results.Length;
for (int i = 0; i < len; i++)
{
actions[i](results[i]);
}
}
I also came up with this... I kinda like it most, but it's a personal preference, I understand it's definitely not the cleanest idea:
using System.Diagnostics;
public static class ArrayExtractor
{
public static void Extract<T1>(this object[] array, out T1 value1)
where T1 : class
{
Debug.Assert(array.Length >= 1);
value1 = array[0] as T1;
}
public static void Extract<T1, T2>(this object[] array, out T1 value1, out T2 value2)
where T1 : class
where T2 : class
{
Debug.Assert(array.Length >= 2);
value1 = array[0] as T1;
value2 = array[1] as T2;
}
}
Of course, I am extending this class up to 10 or 15 arguments.
Usage:
string fileName;
string contents;
ArrayExtractor.Extract(args, out fileName, out contents);
or even better
args.Extract(out fileName, out contents);
where args is, of course, an object array.

How to do template specialization in C#

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.

Categories

Resources