What would be a practical advantage of using generics vs interfaces in this case:
void MyMethod(IFoo f)
{
}
void MyMethod<T>(T f) : where T : IFoo
{
}
I.e. what can you do in MyMethod<T> that you couldn't in the non-generic version? I'm looking for a practical example, I know what the theoretical differences are.
I know that in MyMethod<T>, T will be the concrete type, but nonetheless I will only be able to use it as an IFoo within the body of the method. So what would be a real advantage?
Calling a method through an interface is slower than calling it directly on the concrete type
If the type implementing IFoo is a value type, the non-generic version will box the value of the parameter, and boxing can negatively affect performance (especially if you call this method very often)
If your method returns a value, the generic version can return a T rather than a IFoo, which is convenient if you need to call a method of T on the result
Well, one advantage as mentioned elsewhere, would be the ability to return a specific type of IFoo type if you return a value. But since your question is specifically about void MyMethod(IFoo f), I wanted to give a realistic example of at least one type of situation where using a generic method makes more sense (to me) than the interface. (Yes I spent a bit of time on this, but I wanted to try out some different ideas. :D)
There are two blocks of code, the first is just the generic method itself and some context, the second is the full code for the example, including lots of comments ranging from notes on possible differences between this and an equivalent non-generic implementation, as well as various things I tried while implementing that didn't work, and notes on various choices I made, etc. TL;DR and all that.
Concept
public class FooChains : Dictionary<IFoo, IEnumerable<IFoo>> { }
// to manage our foos and their chains. very important foo chains.
public class FooManager
{
private FooChains myChainList = new FooChains();
// void MyMethod<T>(T f) where T : IFoo
void CopyAndChainFoo<TFoo>(TFoo fromFoo) where TFoo : IFoo
{
TFoo toFoo;
try {
// create a foo from the same type of foo
toFoo = (TFoo)fromFoo.MakeTyped<TFoo>(EFooOpts.ForChain);
}
catch (Exception Ex) {
// hey! that wasn't the same type of foo!
throw new FooChainTypeMismatch(typeof(TFoo), fromFoo, Ex);
}
// a list of a specific type of foos chained to fromFoo
List<TFoo> typedFoos;
if (!myChainList.Keys.Contains(fromFoo))
{
// no foos there! make a list and connect them to fromFoo
typedChain = new List<TFoo>();
myChainList.Add(fromFoo, (IEnumerable<IFoo>)typedChain);
}
else
// oh good, the chain exists, phew!
typedChain = (List<TFoo>)myChainList[fromFoo];
// add the new foo to the connected chain of foos
typedChain.Add(toFoo);
// and we're done!
}
}
Gory Details
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IFooedYouOnce
{
// IFoo
//
// It's personality is so magnetic, it's erased hard drives.
// It can debug other code... by actually debugging other code.
// It can speak Haskell... in C.
//
// It *is* the most interesting interface in the world.
public interface IFoo
{
// didn't end up using this but it's still there because some
// of the supporting derived classes look silly without it.
bool CanChain { get; }
string FooIdentifier { get; }
// would like to place constraints on this in derived methods
// to ensure type safety, but had to use exceptions instead.
// Liskov yada yada yada...
IFoo MakeTyped<TFoo>(EFooOpts fooOpts);
}
// using IEnumerable<IFoo> here to take advantage of covariance;
// we can have lists of derived foos and just cast back and
// forth for adding or if we need to use the derived interfaces.
// made it into a separate class because probably there will be
// specific operations you can do on the chain collection as a
// whole so this way there's a spot for it instead of, say,
// implementing it all in the FooManager
public class FooChains : Dictionary<IFoo, IEnumerable<IFoo>> { }
// manages the foos. very highly important foos.
public class FooManager
{
private FooChains myChainList = new FooChains();
// would perhaps add a new() constraint here to make the
// creation a little easier; could drop the whole MakeTyped
// method. but was trying to stick with the interface from
// the question.
void CopyAndChainFoo<TFoo>(TFoo fromFoo) where TFoo : IFoo
// void MyMethod<T>(T f) where T : IFoo
{
TFoo toFoo;
// without generics, I would probably create a factory
// method on one of the base classes that could return
// any type, and pass in a type. other ways are possible,
// for instance, having a method which took two IFoos,
// fromFoo and toFoo, and handling the Copy elsewhere.
// could have bypassed this try/catch altogether because
// MakeTyped functions throw if the types are not equal,
// but wanted to make it explicit here. also, this gives
// a more descriptive error which, in general, I prefer
try
{
// MakeTyped<TFoo> was a solution to allowing each TFoo
// to be in charge of creating its own objects
toFoo =
(TFoo)fromFoo.MakeTyped<TFoo>(EFooOpts.ForChain);
}
catch (Exception Ex) {
// tried to eliminate the need for this try/catch, but
// didn't manage. can't constrain the derived classes'
// MakeTyped functions on their own types, and didn't
// want to change the constraints to new() as mentioned
throw
new FooChainTypeMismatch(typeof(TFoo), fromFoo, Ex);
}
// a list of specific type foos to hold the chain
List<TFoo> typedFoos;
if (!myChainList.Keys.Contains(fromFoo))
{
// we just create a new one and link it to the fromFoo
// if none already exists
typedFoos = new List<TFoo>();
myChainList.Add(fromFoo, (IEnumerable<IFoo>)typedFoos);
}
else
// otherwise get the existing one; we are using the
// IEnumerable to hold actual List<TFoos> so we can just
// cast here.
typedFoos = (List<TFoo>)myChainList[fromFoo];
// add it in!
typedFoos.Add(toFoo);
}
}
[Flags]
public enum EFooOpts
{
ForChain = 0x01,
FullDup = 0x02,
RawCopy = 0x04,
Specialize = 0x08
}
// base class, originally so we could have the chainable/
// non chainable distinction but that turned out to be
// fairly pointless since I didn't use it. so, just left
// it like it was anyway so I didn't have to rework all
// the classes again.
public abstract class FooBase : IFoo
{
public string FooIdentifier { get; protected set; }
public abstract bool CanChain { get; }
public abstract IFoo MakeTyped<TFoo>(EFooOpts parOpts);
}
public abstract class NonChainableFoo : FooBase
{
public override bool CanChain { get { return false; } }
}
public abstract class ChainableFoo : FooBase
{
public override bool CanChain { get { return true; } }
}
// not much more interesting to see here; the MakeTyped would
// have been nicer not to exist, but that would have required
// a new() constraint on the chains function.
//
// or would have added "where TFoo : MarkIFoo" type constraint
// on the derived classes' implementation of it, but that's not
// allowed due to the fact that the constraints have to derive
// from the base method, which had to exist on the abstract
// classes to implement IFoo.
public class MarkIFoo : NonChainableFoo
{
public MarkIFoo()
{ FooIdentifier = "MI_-" + Guid.NewGuid().ToString(); }
public override IFoo MakeTyped<TFoo>(EFooOpts fooOpts)
{
if (typeof(TFoo) != typeof(MarkIFoo))
throw new FooCopyTypeMismatch(typeof(TFoo), this, null);
return new MarkIFoo(this, fooOpts);
}
private MarkIFoo(MarkIFoo fromFoo, EFooOpts parOpts) :
this() { /* copy MarkOne foo here */ }
}
public class MarkIIFoo : ChainableFoo
{
public MarkIIFoo()
{ FooIdentifier = "MII-" + Guid.NewGuid().ToString(); }
public override IFoo MakeTyped<TFoo>(EFooOpts fooOpts)
{
if (typeof(TFoo) != typeof(MarkIIFoo))
throw new FooCopyTypeMismatch(typeof(TFoo), this, null);
return new MarkIIFoo(this, fooOpts);
}
private MarkIIFoo(MarkIIFoo fromFoo, EFooOpts parOpts) :
this() { /* copy MarkTwo foo here */ }
}
// yep, really, that's about all.
public class FooException : Exception
{
public Tuple<string, object>[] itemDetail { get; private set; }
public FooException(
string message, Exception inner,
params Tuple<string, object>[] parItemDetail
) : base(message, inner)
{
itemDetail = parItemDetail;
}
public FooException(
string msg, object srcItem, object destType, Exception inner
) : this(msg, inner,
Tuple.Create("src", srcItem), Tuple.Create("dtype", destType)
) { }
}
public class FooCopyTypeMismatch : FooException
{
public FooCopyTypeMismatch(
Type reqDestType, IFoo reqFromFoo, Exception inner
) : base("copy type mismatch", reqFromFoo, reqDestType, inner)
{ }
}
public class FooChainTypeMismatch : FooException
{
public FooChainTypeMismatch(
Type reqDestType, IFoo reqFromFoo, Exception inner
) : base("chain type mismatch", reqFromFoo, reqDestType, inner)
{ }
}
}
// I(Foo) shot J.R.!
Doing things like these is easier:
void MyMethod<T>(T f) where T : IFoo, new() {
var t1 = new T();
var t2 = default(T);
// Etc...
}
Also, as you introduce more interfaces, generics may be more "gentle" to callers. For example, you can inherit a class from 2 interfaces and pass it directly, like this...
interface IFoo {
}
interface IBar {
}
class FooBar : IFoo, IBar {
}
void MyMethod<T>(T f) where T : IFoo, IBar {
}
void Test() {
FooBar fb = new FooBar();
MyMethod(fb);
}
...while "interface-only" method would require an "intermediary" interface (IFooBar)...
interface IFoo {
}
interface IBar {
}
interface IFooBar : IFoo, IBar {
}
class FooBar : IFooBar {
}
void MyMethod(IFooBar f) {
}
void Test() {
FooBar fb = new FooBar();
MyMethod(fb);
}
2 years later I found a very simple and useful case. Consider this common pattern:
class MyClass : IDisposable {
public void Dispose() {
if (m_field1 != null) {
m_field1.Dispose();
m_field1 = null;
}
if (m_field2 != null) {
m_field2.Dispose();
m_field2 = null;
}
// etc
}
}
I've always wanted to write a helper method to avoid having to write all this boilerplate for every field:
class MyClass : IDisposable {
static void IfNotNullDispose(ref IDisposable disposable) {
if (disposable != null) {
disposable.Dispose();
disposable = null;
}
}
public void Dispose() {
IfNotNullDispose(ref m_field1);
IfNotNullDispose(ref m_field2);
// etc
}
}
Unfortunately this is illegal in C# because you cannot use an interface for ref parameters, you must use the concrete type you'll pass in and nothing else. So you'd have to write a different method for every single type of field you want to dispose. Oh wait that's exactly what generics do for you:
static void IfNotNullDispose<T>(ref T disposable) where T: class, IDisposable {
if (disposable != null) {
disposable.Dispose();
disposable = null;
}
}
Now everything works as intended!
In this particular case, there is no benefit. In general you wouldn't specify this at a method level, but at a class level. E.g.,
public interface IFoo {
void DoSomethingImportant();
}
public class MyContainer<T> where T : IFoo {
public void Add(T something){
something.DoSomethingImportant();
AddThisThing(something);
}
public T Get() {
T theThing = GetSomeKindOfThing();
return theThing;
}
}
Notice that we require T to implement IFoo because of the Add method where we need to call the DoSomethingImportantMethod implemented by IFoo.
But notice in the Get method that we will return the T provided by end user of this class instead of a plain old IFoo, which alleviates the need for the developer to always cast to their actual concrete T.
Example:
public class Bar : IFoo{
//....
}
MyContainer<Bar> m = new MyContainer<Bar>();
//stuff happens here
Bar b = m.Get();
Note that if I was just returning an IFoo, then I would have to do this at the last line instead:
Bar b = (Bar) m.Get();
The interface method will supply you an f of type IFoo, whereas the generic version will supply you a type T with the constraint that T has to implement IFoo.
The second method would allow you to have some kind of lookup depending on T, as you have a concrete type to work with.
referring to the benchmark reported above
#Branko, calling a method through an interface is actually slower than >a "normal" virtual method call... Here's a simple benchmark: >pastebin.com/jx3W5zWb – Thomas Levesque Aug 29 '11 at 0:33
running the code in Visual Studio 2015 the result are roughly equivalent between Direct call and Through interface:
Direct call: 90,51 millisec; 112,49 millisec; 81,22 millisec
Through interface: 92,85 millisec;90,14 millisec; 88,56 millisec
the code used to benchmark (from http://pastebin.com/jx3W5zWb ) is:
using System;
using System.Diagnostics;
namespace test
{
class MainApp
{
static void Main()
{
Foo f = new Foo();
IFoo f2 = f;
// JIT warm-up
f.Bar();
f2.Bar();
int N = 10000000;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < N; i++)
{
f2.Bar();
}
sw.Stop();
Console.WriteLine("Through interface: {0:F2}", sw.Elapsed.TotalMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < N; i++)
{
f.Bar();
}
sw.Stop();
Console.WriteLine("Direct call: {0:F2}", sw.Elapsed.TotalMilliseconds);
Console.Read();
}
interface IFoo
{
void Bar();
}
class Foo : IFoo
{
public virtual void Bar()
{
}
}
}
}
The generic version allows you to use any type as T - which you for some reason restricted back by using the where clause, whereas your non-generic version supports only something implementing IFoo.
Another (maybe better) question is - are these two options equivalent?
Related
I'm trying to do the following:
public class A
{
}
public class B
{
}
Somewhere along the project I want to have this:
public class C
{
public T func<T>(T obj) [where T can be either of class A or class B]
{
obj.x = 100;
return obj;
}
}
I've been trying:
public T func<T>(T obj) where T: A, B
but this gives me:
The type class constraint 'B' must come before any other constraint.
Can someone explain me how to make func accept only class A or class B?
Exactly as it's described in the question, this job is better handled by overload resolution:
public class C
{
public A func(A obj)
{
obj.x = 100;
return obj;
}
public B func(B obj)
{
obj.x = 100;
return obj;
}
}
But I understand that A and B may be placeholders for any number of types, and it could get tedious to account for them all. In that case, you'll need a common interface that's supported by each of your classes:
interface IBase
{
int x;
}
public class C
{
public IBase func(IBase obj)
{
obj.x = 100;
return obj;
}
}
Note that at this point we still have no need of generics. Additionally, you may need to support a number of types that won't all fit together under a common interface. In this case, still build the interface and put as many types with that interface as possible. If needed, build another interface for a few more types ... and so on... and then between interfaces and specific types you can handle things with overload resolution.
You need some kind of common base for both the classes, either have them implement the same interface as the below code or have them inherit from same class. You can not have a generic constrained to 2 types.
public interface IFooBar
{
void DoThis();
}
public class Foo : IFooBar
{
public void DoThis()
{
//Do something
}
}
public class Bar : IFooBar
{
public void DoThis()
{
//Do something
}
}
public class C
{
public T func<T>(T obj) where T : IFooBar
{
obj.DoThis();
return obj;
}
}
The generics classes are just like any other class, you can't (and shouldn't) have multiple inheritance of classes, you can inherit one class and multiple interfaces.
in your case you should apply an interface on both classes and restrict the generics on that interface.
you can see some documentation in:
Constraints on Type Parameters (C# Programming Guide)
interface IMarkerInterface{} // there is a such pattern called marker
// interface . No need to have methods if there
// is no need for, A and B can just implement it
public class A: IMarkerInterface
{
}
public class B: IMarkerInterface
{
}
public class C
{
public T func<T>(T obj).Where T:IMarkerInterface
{
obj.x = 100;
return obj;
}
}
public T func<T>(T obj) where T: A, B this means T should extend both A and B , but multiple inheritance is not valid in C# ,so it won't work.
You could do one of the following though :
you could make A and B have a common parent via an interface or an abstract class , but that would be code modification.
since both A and B have a default no-arg constructor you could use where T: new().
Also, you can not do obj.x = 100; as there is no way to guarantee thatT will have a instance variable x.
public interface ICloneable<T>
{
T Clone();
}
public Foo: ICloneable<Foo>
{
public Foo Clone()
{
//blah
}
}
Is there any way to constrain T to the type that implements the interface? (Foo in this case). It would be nice to enforce anything implementing ICloneable to return an instance of itself, and not any random type it fancies.
No, basically. You can't do that with generic constraints. Also, you can't stop them implementing the interface multiple times with different T (as long as those T satisfy any where constraints, none in this case).
There is no where constraint that allows restriction to the implementing type.
You kinda sorta can do it as a method parameter restriction, but it isn't really satisfactory:
public static T SuperClone<T>(this T original) where T : ICloneable<T> {...}
Note that it is possible to use Code Contracts to express this. Normally this is checked at runtime but it's possible to get a compile-time warning (see the notes later):
It goes something like this:
[ContractClass(typeof(CloneableContract<>))]
public interface ICloneable<out T>
{
T Clone();
}
[ContractClassFor(typeof(ICloneable<>))]
internal abstract class CloneableContract<T>: ICloneable<T>
{
public T Clone()
{
Contract.Ensures(Contract.Result<object>() != null);
Contract.Ensures(Contract.Result<object>().GetType() == this.GetType());
return default(T);
}
}
Then if you have the following class definitions:
public class GoodFoo: ICloneable<GoodFoo>
{
public virtual GoodFoo Clone()
{
var result = new GoodFoo();
Contract.Assume(result.GetType() == this.GetType());
return result;
}
}
public class BadFoo: ICloneable<object>
{
public object Clone()
{
return new object(); // warning : CodeContracts: ensures unproven: Contract.Result<object>().GetType() == this.GetType()
}
}
public class AlsoBad: GoodFoo
{
public override GoodFoo Clone()
{
return new GoodFoo(); // warning : CodeContracts: ensures unproven: Contract.Result<object>().GetType() == this.GetType()
}
}
This will work OK at runtime:
var good = new GoodFoo();
good.Clone();
These will cause runtime Code Contract failures:
var bad = new BadFoo();
bad.Clone();
var alsoBad = new BadFoo();
alsoBad.Clone();
Note that you can get a compile time time warning.
If you do a full Code Contracts Static Checking compile, you will see warnings about "ensures unproven" for the implementations of Clone() for class BadFoo and class AlsoBad.
There is no warning for GoodFoo.Clone() because of the Contract.Assume(result.GetType() == this.GetType()); in its implementation.
However, Code Contracts Static Checking is (in my opinion) still too slow for anything but occasional checking, but your mileage may vary...
Here's my best attempt to recreate the situation.
public interface IFoo
{
}
public class Foo : IFoo { }
public class Bar : IFoo { }
public class CollectionOf<T> : List<IFoo>
{
}
public class Bars : CollectionOf<Bar>
{
}
public class Test
{
public void Test()
{
CollectionOf<IFoo> bars = new Bars();
}
}
Compiler complains on the instantiation. Bars is a collection of IFoos. Is this one of those covariance/contravariance issues?
Yes.
Think about it for a second; bars should legally be able to hold objects of any type that implement IFoo. However, an object of type Bars can only hold objects of type Bar.
Using your code this would be allowed, which is obviously wrong.
CollectionOf<IFoo> bars = new Bars();
bars.Add( new Foo() ); // Uh oh!
That would effectively break the type safety afforded to you via generics.
Yes it is.
If this was allowed, you would be able to place any object into that collection, as long as it implemented the IFoo interface, but that wouldn't be safe for the collection.
Let me illustrate:
var b = new Bars();
CollectionOf<IFoo> bars = b;
bars.Add(Dummy); // implements IFoo, but does not descend from Bar
At this point, what does b contain? An object of type Dummy? That would be bad, and thus this is not allowed in the first place.
The fix, if there is one would depend on what it is that's not working for you. I can get your example to compile in two ways, either use IEnumerable or define your CollectionOf as an interface with the out generic modifier. Whether either is a fix for you I don't know:
public interface IFoo { }
public class Foo : IFoo { }
public class Bar : IFoo { }
public interface CollectionOf<out T> : IEnumerable<IFoo> { }
public class Bars : CollectionOf<Bar> { }
public class Test
{
public void Test()
{
IEnumerable<IFoo> bars1 = new Bars();
CollectionOf<IFoo> bars2 = new Bars();
}
}
Consider the following code:
abstract class Foo<T>
where T : Foo<T>, new()
{
void Test()
{
if(Bar != null)
Bar(this);
}
public event Bar<T> Bar;
}
delegate void Bar<T>(T foo)
where T : Foo<T>, new();
The line Bar(this) results in the following compiler Error:
Argument type Foo<T> is not assignable to parameter type T
T is constrained to Foo<T> as I want derived classes to basically tell the base class their type, so that the type can be used in the event callback in order to save the implementor from having to cast the callback argument to the derived type.
I can see the code doesn't quite work but I'm having a bit of a blockage as to how to do this correctly without ending up with a generic delegate that can be used for any old thing. I'm also not quite sure why the T constraint doesn't create a compiler error considering it seems to be recursive.
EDIT
I need to clarify this I think! Here's a new example which, I hope will be much clearer. Note below that the OnDuckReady event handler below generates a compiler error.
How do I get the event to pass in the correct type?
abstract class Animal<T>
where T : Animal<T>, new()
{
void Test()
{
if(AnimalReady != null)
AnimalReady(this);
}
public event AnimalHandler<T> AnimalReady;
}
delegate void AnimalHandler<T>(Animal<T> animal)
where T : Animal<T>, new();
class Duck : Animal<Duck>
{
public void FlyAway()
{
}
}
class Test
{
void Main()
{
Duck duck = new Duck();
duck.AnimalReady += OnDuckReady; // COMPILER ERROR
}
void OnDuckReady(Duck duck)
{
duck.FlyAway();
}
}
You can cast 'this' to T:
Bar((T)this);
This however will fail if you have the following:
public class MyFoo : Foo<MyFoo> { }
public class MyOtherFoo : Foo<MyFoo> { }
Because 'MyOtherFoo' is not an instance of 'MyFoo'. Take a look at this post by Eric Lippert, one of the designers of C#.
The code would be clearer if you didn't use "Bar" for two purposes. That having been said, I think what's needed is to use a generic with two parameters (e.g. T and U) such that T derives from U, and U derives from Foo. Alternatively, it's possible to do some nice things with interfaces. A useful pattern is to define:
interface ISelf<out T> {T Self<T> {get;}}
and then, for various interfaces that one might want to combine in an object:
interface IThis<out T> : IThis, ISelf<T> {}
interface IThat<out T> : IThat, ISelf<T> {}
interface ITheOtherThing<out T> : ITheOtherThing, ISelf<T> {}
If classes that implement IThis, IThat, and ITheOtherThing also implement ISelf<theirOwnTypes>, one can then have a routine whose parameter (e.g. "foo") has to implement both IThis and IThat accept the parameter as type IThis. Parameter "foo" will be of type IThis (which in turn implements IThis) while Foo.Self will be of type IThat. Note that if things are implemented this way, one may freely typecast variables to any desired combination of interfaces. For example, in the above example, if the object passed as "foo" was a type which implemented IThis, IThat, ITheOtherThing, and ISelf<itsOwnType> it could be typecast to ITheOtherThing>, or IThis, or any other desired combination and arrangement of those interfaces.
Really a pretty versatile trick.
Edit/Addendum
Here's a somewhat more complete example.
namespace ISelfTester
{
interface ISelf<out T> {T Self {get;} }
interface IThis { void doThis(); }
interface IThat { void doThat(); }
interface IOther { void doOther(); }
interface IThis<out T> : IThis, ISelf<T> {}
interface IThat<out T> : IThat, ISelf<T> {}
interface IOther<out T> : IOther, ISelf<T> {}
class ThisOrThat : IThis<ThisOrThat>, IThat<ThisOrThat>
{
public ThisOrThat Self { get { return this; } }
public void doThis() { Console.WriteLine("{0}.doThis", this.GetType()); }
public void doThat() { Console.WriteLine("{0}.doThat", this.GetType()); }
}
class ThisOrOther : IThis<ThisOrOther>, IOther<ThisOrOther>
{
public ThisOrOther Self { get { return this; } }
public void doThis() { Console.WriteLine("{0}.doThis", this.GetType()); }
public void doOther() { Console.WriteLine("{0}.doOther", this.GetType()); }
}
class ThatOrOther : IThat<ThatOrOther>, IOther<ThatOrOther>
{
public ThatOrOther Self { get { return this; } }
public void doThat() { Console.WriteLine("{0}.doThat", this.GetType()); }
public void doOther() { Console.WriteLine("{0}.doOther", this.GetType()); }
}
class ThisThatOrOther : IThis<ThisThatOrOther>,IThat<ThisThatOrOther>, IOther<ThisThatOrOther>
{
public ThisThatOrOther Self { get { return this; } }
public void doThis() { Console.WriteLine("{0}.doThis", this.GetType()); }
public void doThat() { Console.WriteLine("{0}.doThat", this.GetType()); }
public void doOther() { Console.WriteLine("{0}.doOther", this.GetType()); }
}
static class ISelfTest
{
static void TestThisOrThat(IThis<IThat> param)
{
param.doThis();
param.Self.doThat();
}
static void TestThisOrOther(IThis<IOther> param)
{
param.doThis();
param.Self.doOther();
}
static void TestThatOrOther(IThat<IOther> param)
{
param.doThat();
param.Self.doOther();
}
public static void test()
{
IThis<IThat> ThisOrThat1 = new ThisOrThat();
IThat<IThis> ThisOrThat2 = new ThisOrThat();
IThis<IOther> ThisOrOther1 = new ThisOrOther();
IOther<IThat> OtherOrThat1 = new ThatOrOther();
IThis<IThat<IOther>> ThisThatOrOther1 = new ThisThatOrOther();
IOther<IThat<IThis>> ThisThatOrOther2a = new ThisThatOrOther();
var ThisThatOrOther2b = (IOther<IThis<IThat>>)ThisThatOrOther1;
TestThisOrThat(ThisOrThat1);
TestThisOrThat((IThis<IThat>)ThisOrThat2);
TestThisOrThat((IThis<IThat>)ThisThatOrOther1);
TestThisOrOther(ThisOrOther1);
TestThisOrOther((IThis<IOther>)ThisThatOrOther1);
TestThatOrOther((IThat<IOther>)OtherOrThat1);
TestThatOrOther((IThat<IOther>)ThisThatOrOther1);
}
}
}
The thing to note is that some classes implement different combinations of IThis, IThat, and IOther, and some methods require different combinations. The four non-static classes given above are all unrelated, as are the interfaces IThis, IThat, and IOther. Nonetheless, it is possible for method parameters to require any combination of the interfaces provided that implementing classes follow the indicated pattern. Storage locations of a "combined" interface type may only be passed to parameters which specify the included interfaces in the same order. An instance of any type which properly implements the pattern, however, may be typecast to any "combined" interface type using any subset of its interfaces in any order (with or without duplicates). When used with instances of classes that properly implement the pattern, the typecasts will always succeed at run-time (they could fail with rogue implementations).
delegate void Bar<T>(Foo<T> foo) where T : Foo<T>, new();
It works great. I tested it.
here is the test code
public abstract class Foo<T> where T :Foo<T> {
public event Bar<T> Bar;
public void Test ()
{
if (Bar != null)
{
Bar (this);
}
}
}
public class FooWorld : Foo<FooWorld> {
}
public delegate void Bar<T>(Foo<T> foo) where T : Foo<T>;
class MainClass
{
public static void Main (string[] args)
{
FooWorld fw = new FooWorld ();
fw.Bar += delegate(Foo<FooWorld> foo) {
Console.WriteLine ("Bar response to {0}", foo);
};
fw.Test ();
}
}
Suppose I write a library with the following:
public class Bar { /* ... */ }
public class SomeWeirdClass<T>
where T : ???
{
public T BarMaker(Bar b)
{
// ... play with b
T t = (T)b
return (T) b;
}
}
Later, I expect users to use my library by defining their own types which are convertible to Bar and using the SomeWeirdClass 'factory'.
public class Foo
{
public static explicit operator Foo(Bar f)
{
return new Bar();
}
}
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
Foo f = weird.BarMaker(b);
}
}
this will compile if i set where T : Foo but the problem is that I don't know about Foo at the library's compile time, and I actually want something more like where T : some class that can be instantiated, given a Bar
Is this possible? From my limited knowledge it does not seem to be, but the ingenuity of the .NET framework and its users always surprises me...
This may or not be related to the idea of static interface methods - at least, I can see the value in being able to specify the presence of factory methods to create objects (similar to the same way that you can already perform where T : new())
edit: Solution - thanks to Nick and bzIm - For other readers I'll provide a completed solution as I understand it:
edit2: This solution requires Foo to expose a public default constructor. For an even stupider better solution that does not require this see the very bottom of this post.
public class Bar {}
public class SomeWeirdClass<T>
where T : IConvertibleFromBar<T>, new()
{
public T BarMaker(Bar b)
{
T t = new T();
t.Convert(b);
return t;
}
}
public interface IConvertibleFromBar<T>
{
T Convert(Bar b);
}
public class Foo : IConvertibleFromBar<Foo>
{
public static explicit operator Foo(Bar f)
{
return null;
}
public Foo Convert(Bar b)
{
return (Foo) b;
}
}
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
Foo f = weird.BarMaker(b);
}
}
edit2: Solution 2: Create a type convertor factory to use:
#region library defined code
public class Bar {}
public class SomeWeirdClass<T, TFactory>
where TFactory : IConvertorFactory<Bar, T>, new()
{
private static TFactory convertor = new TFactory();
public T BarMaker(Bar b)
{
return convertor.Convert(b);
}
}
public interface IConvertorFactory<TFrom, TTo>
{
TTo Convert(TFrom from);
}
#endregion
#region user defined code
public class BarToFooConvertor : IConvertorFactory<Bar, Foo>
{
public Foo Convert(Bar from)
{
return (Foo) from;
}
}
public class Foo
{
public Foo(int a) {}
public static explicit operator Foo(Bar f)
{
return null;
}
public Foo Convert(Bar b)
{
return (Foo) b;
}
}
#endregion
public class Demo
{
public static void demo()
{
Bar b = new Bar();
SomeWeirdClass<Foo, BarToFooConvertor> weird = new SomeWeirdClass<Foo, BarToFooConvertor>();
Foo f = weird.BarMaker(b);
}
}
Sounds like you found a solution to the larger problem. To answer your specific question: no, neither C# nor the CLR support the "backwards" generic type parameter constraint. That is,
class C<T> where Foo : T
"T must be Foo or a type which Foo converts to" is not supported.
There are languages that have that sort of constraint; IIRC Scala is such a language. I suspect this feature would be handy for certain uses of contravariant interfaces.
I don't think there is necessarily a syntactically cool way to do this built into the language. One possible solution to your problem could be to define a convertible interface:
public interface IConvertible<T>
where T : new() // Probably will need this
{
T Convert();
}
Then your class could be:
public class Foo : IConvertible<Bar>
{
}
I think this gets you close to where you want to be... All the Foo's and Bar's in your question sometimes make it hard to determine exactly what your intent is. Hope this helps.
Edit: Added where constraint... you will probably have to be able to create a new instance in your convertible class.
Edit 2: Made Foo inherit from ICovertible<Bar>
You could make a detour via an interface which is used as a type constraint.
For example, where T : IComparable<U> is used to constrain the type to something that can be compared to another thing, which must express this ability by implementing IComparable<another>. If you had an interface ICastableFrom<T>, you could achieve what you want by forcing them to implement ICastableFrom<Bar>.
Rather than go through the trouble of defining an interface and modifying your class to implement that interface, why not just do this?
public class SomeWeirdClass<T>
{
// aside: why is this method called 'BarMaker' if it returns a T?
public T BarMaker(Bar b, Func<Bar, T> converter)
{
// ... play with b
return converter(b);
}
}
Then in the event that you are dealing with an object of a type T to which Bar can be directly cast, this method could be called simply as follows:
var someWeirdObject = new SomeWeirdClass<Foo>();
var someBar = new Bar();
var someFoo = someWeirdObjcet.BarMaker(someBar, bar => bar as Foo);
By the way (since the Func<T, TResult> delegate emerged in .NET 3.5), you could also use Converter<TInput, TOutput> (which is exactly the same) for the converter parameter.