For a project I'm on I'm unfortunately stuck with .NET 2.0 (many of our target machines are still Windows XP), which means no Optional type as Nuget's Optional library requires .NET 3.5.
Fortunately, rolling your own Optional type is pretty easy, but I've encountered one issue.
I would like something like the following:
class Optional<T> : (IComparable<Optional<T>> when T : IComparable<T>)
That is, I want my Optional type to implement Comparable, but only when the underlying type is Comparable.
The above syntax is sadly not valid, but is there a way achieve what I'm looking for?
Indeed this problem isn't confined to Optional, it will apply to any container type one wants to define that can implement it's internal type's interfaces.
I do realise I could do this:
class Optional<T>
class ComparableOptional<T> : Optional<T>, Comparable<ComparableOptional<T>>
where T : Comparable<T>
But this seems a bit silly, as then we really have to go down this rabbit hole:
class Optional<T>
class EquatableOptional<T> :
Optional<T>,
IEquatable<EquatableOptional<T>>
where T : IEquatable<T>
class ComparableOptional<T> :
EquatableOptional<T>,
IComparable<ComparableOptional<T>>,
IEquatable<ComparableOptional<T>>
where T : IComparable<T>
Furthermore, if T is Enumerable, Optional<T> can also be Enumerable (returning an empty enumerator if there is no value) so then we've got even more classes.
As Enumerable is orthogonal to Equatable and Comparable, we'd really need the following classes:
class Optional
class EquatableOptional
class ComparableOptional
class EnumerableOptional
class EnumerableEquatableOptional
class EnumerableComparableOptional
to cover all cases. Add another orthogonal interface and you've got 12 classes.
Is there a less messy approach that allows me to define interfaces conditionally? This seems like a common issue with any collection.
What you want to do infringes on the intention of how generics work in C#.
You're essentially arguing that type safety should be used as type possibility. Which is against the current C# ideology where you know a type's definition (and which methods and properties it exposes) for a fact.
The correct approach would be to have a second ComparableOptional<T> which derives from Optional<T> but adds an additional constraint:
class ComparableOptional<T> : Optional<T> where T : Comparable<T>
There is no benefit to your suggestion, other than the lazy approach of wanting to mash two different classes together. Even if the language would allow you to do so, I see no discernible benefit to this approach (compared to ComparableOptional<T>) but it does introduce a whole range of runtime errors that you can now encounter.
class Optional<T> : (IComparable<Optional<T>> when T : IComparable<T>) {}
Suppose everything works the way you expect it to.
var optionalPerson = new Optional<Person>() { Person = myPerson };
var optionalPerson2 = new Optional<Person>() { Person = myPerson2 };
int result = optionalPerson.CompareTo(optionalPerson2);
Should this work? In C# currently, it doesn't. But according to you, it should be able to if Person : IComparable<Person>. Your argument should be something like this:
Since the compiler sees me use the type Person : IComparable<Person>, it should be able to deduce that Optional<T> must now implement IComparable<T> and therefore the CompareTo() should be available.
The solidity of your argument rests solely on the fact that you know for a fact (at compile time) that the type you're using implements the needed interface.
But what about this code:
public void DoSomething<T>(Optional<T> opt1, Optional<T> opt2)
{
int result = opt1.CompareTo(opt2);
}
Should this work? You can't know, since you don't know which type will be used! Compounding the issue even further:
public void DoSomething(string optionalType, object opt1, object opt2)
{
var castObj = Convert.ChangeType(opt1, Type.GetType(optionalType)));
var castObj2 = Convert.ChangeType(opt2, Type.GetType(optionalType)));
int result = castObj .CompareTo(castObj2);
}
This method passes the used type as a string. So now you would expect the compiler to check the value of the string to figure out whether or not the generic type constraint of the type that is represented in the string implements a particular interface.
WHat if that string is retrieved from a database or external web service? Is the compiler now required to have an active database/web connection before it can decide whether your code is valid?
This is running out of hand.
Your likely counterarguments:
As long as I only use this method with types that implement IComparable<T>, the compiler should not throw an error. When I use a type that does not implement IComparable<T>, it should throw an error on the int result line.
That is not intuitive, and is going to lead to developer confusion.
The compiler should always assume that conditional generic type constraints are true.
So how would you handle mutually exclusive conditional generic type constraints, which logically will never both be true?
Welcome to the world of debugging hell. This is bad practice for the same reason that you shouldn't use dynamic over strongly typed approaches: it makes code considerably harder to maintain and develop.
Such an approach requires much more runtime testing to ensure that you haven't made a mistake somewhere that will blow up in your face. And runtime testing is a flawed approach.
Related
This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 4 years ago.
I defined various classes like this:
public class Subclass<T> : BaseObject<T>, IObject, IObject<T> { ... }
BaseObject<T> contains all the functionality I need. IObject<T> allows it to be accessed between projects. IObject allows collections to be created: List<IObject>.
BaseObject<T> and IObject<T> have a property T Value;
So I have
public class BaseObject<T> // T is double, int, decimal, long, short, int - in fact anything enumerable
: IObject, IObject<T>
{
[...]
T Value;
[...]
}
The problem I am trying to solve is how to unpack this by type T.
I want to write this function but don't know how in C#:
public void DoProcessing(List<IObject> objectsToBeProcessed)
{
foreach(dynamic singleObject in objectsToBeProcessed)
{
Type unpackedType = [somehow retrieve the type]
BaseObject<unpackedType.GetType()> unpackedObject = [do some kind of conversion of singleObject];
ProcessorClass<unpackedType.GetType()> processor = new ProcessorClass<unpackedType.GetType()>();
processor.Process(unpackedObject);
}
}
I'm finding this quite hard to put into words but I hope that this explanation gets the idea across. Basically I lose the type information when I build the List<IObject> and I need it back later on when I pass it across into another assembly. I want a single central DoProcessing method that can then delegate by type to instances of generics.
How can I get the type information back?
I understand that generics need a type known at compile-time. But this is situation where you only know the type at runtime. The dynamic keyword allows the collection to be iterated, but I haven't found a way to create the bit inside the loop.
Or should I just force everything to a double in BaseObject and then cast it back locally in some way?
I'm a bit lost on this and feel I am missing something obvious. Any ideas welcome.
POSTSCRIPT - CLARIFICATION
The purpose of this is to separate the code-base into two assemblies:
The assembly with BaseObject<T> allows customers and third parties
to write their own business logic which we don't need to see. They
simply subclass the BaseObject into their own code.
The assembly with IObject & IObject<T> contains generic business
logic that we are creating.
We need this separation in so customers can develop their own libraries of code without having to submit it to us. They just send us a list of List<IObject> and we do the rest, calling their subclasses back as necessary.
Surely it is possible!
ALTERNATIVELY
Can anyone suggest a better architectural solution to the two assembly solution I have described i.e. concrete classes in customer code assembly & abstract/interfaces in our framework assembly.
SOLUTION
OK so I've found a simpler solution. Late-binding via Reflection is doable but is hard to implement with my nuanced object model.
Instead, I have replaced the generic type T and implemented a property which is an enum of
public enum ValueType
{
Double,
Boolean,
Integer,
...
}
I then implement overloaded constructors, added this property to the non-generic interface IObject and have removed the generic interface IObject<T> as it's no longer needed.
Returning the value as double or bool is then handled by
public double AsDouble();
public bool AsBoolean();
public int AsInt();
...
in the interface.
It's not elegant or theoretically pure but it means I don't lose type information and can treat instances all the same. I just unpack the ValueType and choose different behaviour programmatically. It also avoids using the dynamic keyword as all values are implemented as double so looping is easy to implement.
On the plus side I have removed a lot of constraints on generics as they were needed up the inheritance hierarchy. It was getting really complicated and the compilation errors were getting too difficult to unravel.
It feels a bit unsatisfactory from a purist perspective, but MongoDB does something similar so that's good enough for me.
I do feel however that C# is "unfinished" in this area and needs a way to upcast or downcast more easily. It's just such an obvious thing to add.
Maybe the Reflection can be wrapped up somehow to make it transparent to the programmer.
Over-engineering, pragmatism and purism. These are the things that weigh on me...
This should be enough to return the type of the object inside your loop:
Type unpackedType = singleObject.GetType();
UPDATE:
Thanks to some help it seems to be a bug with Unity's compiler as it doesn't happen outside of Unity. I am currently submitting a bug report and I'll try and find a work around.
I originally posted this to reddit but I think I will need all the help I can get. Here is it copied over:
Not sure how it has come to this, but in order to maintain maximum extendability I have had to use all this techniques.
In short, this works
ICombatEffect<IEffectReturn> com = new TackleEffectBase(this);
but when I try this
ICombatEffect<IEffectReturn>[] EffectsArra = ICombatEffect<IEffectReturn>[]{new TackleEffectBase(this);}
or this
List< ICombatEffect<IEffectReturn>> EffectsList = new List< ICombatEffect<IEffectReturn>>{new TackleEffectBase(this)}
I get an ArrayTypeMismatchException.
Now for the details: (although I've condensed this a lot)
p
ublic interface ICombatEffect<out T> where T : IEffectReturn
{
T Effect(CombatProcessor combat);
}
public abstract class EffectTemplate<T1> : ICombatEffect<T1> where T1 : IEffectReturn
{
public abstract T1 Effect(CombatProcessor combat);
}
public abstract class DamageBaseTemplate : EffectTemplate<DamageBaseModifier>
{}
DamageBaseModifier : IEffectReturn
public class TackleEffectBase : DamageBaseTemplate
I've left out all of the functional stuff so I can let the types do the talking.
The premise is that I each ICombatEffect has an Effect Method. The Effect method must always have a return type that implements IEffectReturn interface. I need to preserve the return type of each ICombatEffect as it is used for sorting later.
Since I have quite a lot of functional code, I've put in the abstract class EffectTemplate. I've read a lot about this sort of style and the trick is to make the interface non-generic. I do not have that luxury unfortunately as sometimes I will not be using the template. So I have set up the interface with a covariant generic type. The abstract class sort of has its generic type linked so they will be the same. This took me a bloody long time to figure out and I was pretty disappointing when I couldn't get it to run today.
I'm no expert on generics but here is my theory on why I can create a single instance but not add that to a collection. When you declare the single instance it goes through and sets all the generics to the instance's type. For a collection, you can't really make its generics concrete, they are only there to see if it slots in.
I'm pretty ok with tearing this down for a better solution as long as it fulfills my needs, but I'm pretty darn curious about this solution. I thought myself so clever when I got all these cascading generic types to work, but alas.
Imagine the following two classes:
class A
{
public A()
{
}
}
class B : A
{
public B()
{
}
}
Is it possible for me to define A, or alternatively an interface, in a way that forces class B to have a parameterless constructor? Or, more generalized, a constructor (or static method) that is able to create an instance of type B with a given signature?
I do not want to restrict class B to only be constructible using that signature, but I want to be sure that class B can be constructed with this signature (be it parameterless, or specifying certain parameters).
To be clear: I am not searching for a solution that would require me to use Reflection or any other method to figure that out at runtime (I don't have a problem with it, but it would make the code less readable, and generally seems like a bad idea in this case).
Is there a way to accomplish this?
I wrote a blog post that goes more in-depth about what I am trying to achieve here
There is no interface or base type that you can apply to the type to ensure it has a parameterless constructor. The only context in which you can make such a contraint is generic constraints:
public static void Foo<T>()
where T : new() {}
In such a case the only types that can be used with Foo must have a parameterless constructor.
You can define factory for instantiating objects of type A (and derived types):
interface IFactory<T> where T : A
{
T Create(int i);
T Create(string s);
// and so on...
}
and require factory implementation, when you want to create an object.
This will make sure calling code in compile time, that it tries to create an object with the given set of parameters.
Of course, there's nothing preventing from NotImplementedException from concrete IFactory<T> implementation at run-time.
This is a followup, since I did a little bit of research and at least managed to come up with an answer that is somewhat satisfying.
So after digging around a while and trying to figure out how the built-in serialization/deserialization in C# works, I found out that C# has a method called GetUninitializedObject(). This method seems like a hack, since it just avoids calling the constructor of the object in the first place, but it at least gives me a way to accomplish what I originally wanted: Being able to deserialize an object of an arbitrary type. Using this, I am able to use methods on the uninitialized created objects (and forcing their implementation via an interface).
I find this to be fitting my needs, although it does not do what I originally wanted to, it allows me to implement a pattern that works for my purposes.
Best Regards
//this class (or interface if you like) is set up as generic...
public abstract class GenericBase<T>
{
public T PerformBasicTask(T in) { ... }
}
//... but is intended to be inherited by objects that close the generic...
public class ConcreteForDates:GenericBase<DateTime>
{
public DateTime PerformSpecificTask(DateTime in) { ... }
}
//... so that consuming code never knows that a generic is involved
var myDateConcrete = new ConcreteForDates(); //look ma, no GTP!
//These two methods look alike, and there is no generic type inference,
//even with PerformBasicTask().
var basicResult = myDateConcrete.PerformBasicTask(DateTime.Now);
var specificResult = myDateConcrete.PerformSpecificTask(DateTime.Today);
//does not compile because T is understood by inheritance to be a DateTime,
//even though PerformBasicTask()'s implementation may well handle an int.
var anotherBasicResult = myDateConcrete.PerformBasicTask(1);
I've seen and used this pattern several times, and it's very useful for providing common functionality across a series of type-specific subclasses. For instance, this could be a model for Controllers/Presenters specific to a type of domain object that is central to the page(s) the class is used to control; basic operations like retrieval/persistence may use 100% common functionality, but binding/unbinding may be very specific.
Is there a name for this pattern of generic declaration without exposing the generic to the end user?
I believe this is not a pattern but specifics of Generic Type subsystem of the .NET Framework which generates concrete type in runtime by substituting generic type parameter by a concrete type (in your example DateTime). All other things regarding sharing a common behaviour is known as Inheritance
If I were to name it, I would call it Specifics and I agree with Aliostad in that it is an anti-pattern.
Generics is used to re-use a behaviour that needs to be described beyond the type - or at least within the restrictions enforced by the where clause.
The example you have seen, IMHO, is a generics anti-pattern. Type should not matter or if it does, should only matter if it is defined in the restrictions - i.e. where clause.
So basically, a generic abstract class which expects all subclasses to implement an abstract, is not using the genericness. I cannot just simply start using Generic<MyType> which is the point of generics.
I believe that defeats the point.
In this case there is a slight benefit in using a generic abstract class/interface and that is type safety achieve for PerformSpecificTask.
UPDATE
I knew it is a contentious issue and I would be fired at left and right, but I believe it is the case.
A class can happily subclass a generic class and add more functionality. But in this case, it is the extra functionality that defines the identity of that class. When I cannot just say Generic<MyOwnTypeOfVolition> then I have defeated the objective of generics. Sometimes, however, it is not the generics which I am concerned with - it is the interface which seems to be the case here.
UPDATE 2
A classic example, is IConvertible in .NET Framework.
You could setup a generic interface/abstract class for it and ask all subclasses to implement it, but the framework makes it an optional case and supports it only for classes implementing the interface.
Recently I tried to create a generic subclass by implementing a generic interface.
public interface IModule<T> where T : DataBean { ..... }
public class Module<T> : IModule<T> where T : DataBean { .... }
It seems I can't rely on any of T's restrictions as were defined in the base interface,
and I need to re-declare them myself.
MSDN just provided:
When using the subclass generic type
parameters, you must repeat any
constraints stipulated at the base
class level at the subclass level. For
example, derivation constraint
Why isn't it possible to infer the constraints from the base class/interface ?
I can't come up with any reason that the c# couldn't theoretically copy over constraints. But the documented behavior of making us copy (or augment) them explicitly seems to be the simplest way for usability.
public class A{}
public class B : A {}
public class X<T> where T: A {}
public class Y<T> : X<T> where T: B { }
In the above, note that I did not have to explicty copy over the constraint on Y<T>, because a B is always an A.
Now lets look at what happens if the "compiler automatically copies over constraints". Let's say I define Y<T> without constraints and the compiler places them automatically. I use Y<T> in lots of code. Then I change the constraints on the declaration of X<T> to include some new interface.
The compiler errors for changing the declaration of X<T> are at the sites where I use Y<T> !
With the way the c# compiler currently works, the compiler errors are at the usages of X<T>, as I would expect if I change it in a breaking way.
So while it would be convenient in some scenarios, it would also be somewhat confusing in others. While both are valid approaches, I would assume (note that I'm not able to read the minds of the c# design team) that it was a judgement call and not a purely technical one.
I say "not purely technical", but I can certainly imagine some interface scenarios where it would be somewhat simpler to verify that all constraints are met, rather than produce the simplest constraint that meets all required inherited constraints.
Standard C# team wisdom. Declarations should be self-documenting. And most of all, a change in one type declaration should not alter the behavior of an unrelated other type without generating a diagnostic. The -100 points principle put into design is another take on that.
The constranints on the interface are too vauge to tell the compiler what constraints the Module class should have. For example, the Module class could have a constraint on a super-class (inherited class) of DataBean.
I don't know the wisdom of the C# designers. Because the constraints can be different, I think a decision was made to have the developer explicitly declare the constraint rather than having the compiler make assumptions.