Closed jvmlet closed 11 months ago
How would it be used? This would give fluent syntax. Casting and LINQ Cast<T>()
are not equivalent because this is compile-type-safe. Is there more to it?
Here are some quick thoughts. AutoAs could have additional parameters [GenerateAutoAs(Sources=AutoAsSources.All, InterfaceType=typeof(IMyInterface1))]
Using Sources consumer could filter which AsX method should be generated. Here are some flags:
BaseTypeInterfaces - recursively take interfaces from all base classes
EntireInterfaceHierarchy - take base interface for every interface
SkipBaseSystemInterfaces - this would skip interfaces like IEnumerable
SkipNongenericBaseSystemInterfaces - this would skip interfaces like IEnumerable
ExplicitInterfacesOnly - only take interfaces that are listed directly, skipping ones from base hierarchy
Example with unknown generic tied to class:
public partial class MyClass<T> : IMy1<T> {}
public partial class MyClass<T> {
public IMy<T> AsMy1() => this;
}
Example with known generic:
public partial class MyClass : IMy1<int> {}
public partial class MyClass {
public IMy<int> AsMy1() => this;
}
Problematic example:
public partial class MyClass : IMy1<int>, IMy1<string> {}
public partial class MyClass {
public IMy<int> AsMy1() => this;
public IMy<string> AsMy1() => this;
}
Another problematic example:
public partial class MyClass : IMy1<int>, IMy1<int, int> {}
public partial class MyClass {
public IMy<int> AsMy1() => this;
public IMy<int, int> AsMy1() => this;
}
Thanks for the quick response.
The intention is to allow easier API exploration, no need to Show me your type hierarchy
to
ISomeFeature someFeature = obj; someFeature.Invoke()
,
instead , just
obj.AsSomeFeature().Invoke()
.
About problematic use-cases - just post-index the ambiguous types :
public partial class MyClass : IMyInterface, IMyInterface<int>, IMyInterface<string>, IMyInterface<int, int> {}
public partial class MyClass {
public IMyInterface AsMyInterface_0() => this;
public IMyInterface<int> AsMyInterface_1() => this;
public IMyInterface<string> AsMyInterface_2() => this;
public IMyInterface<int, int> AsMyInterface_3() => this;
}
I would say that the strategy would be EntireInterfaceHierarchy | SkipBaseSystemInterfaces
Another thought - the top level interface types from this
and base class are enough, because you can call interface's inherited methods :
public interface IA{
public void DoA() ;
}
public interface IB:IA{
public void DoB() ;
}
public class B:IB{
} ;
new B().AsB().DoA():
I've made 1.0.32-pre preview with requested feature.
Source generator have two parameters: EntireInterfaceHierarchy=false
, SkipSystemInterfaces=true
. Those are default values.
In the case of ambiguous method names every method will get _N suffix which is stable-sorted (by the number or generic arguments, then by the name of the type).
In the case of name conflict (targeted method name already exists) generator should make compiler error but that part is not implemented yet. Please note that some compiler error codes are not set up correctly, I will do this tomorrow.
Great, thanks, I will give it a try next week.
@beakona , just one comment :
EntireInterfaceHierarchy - take base interface for every interface
is redundant, because no need to cast interface to base interface to call it's method.
You can new B().AsB().DoA();
Yes, it's redundant, but if someone don't know type hierarch and want to explore interfaces it could opt-in for all interfaces.
I've made separate git repository AutoAs specificaly for this source generator. I'm planning to remove it from AutoInterface because each time compiler activates this source generator it would pass semantic elements twice, first time to AutoInterface and second time to GenerateAutoAs.
Thanks for quick implementation, @beakona , I find it very useful. Pure joy !!!
Proposal : Given the class
generates