146 строки
3.7 KiB
Markdown
146 строки
3.7 KiB
Markdown
|
|
# C# Language Design Notes for Oct 17, 2018
|
|
|
|
## Agenda
|
|
|
|
1. Open issues with default interface methods
|
|
2. Target typed new with default constructors on structs
|
|
|
|
## Discussion
|
|
|
|
### Issues in default interface methods
|
|
|
|
Link: https://github.com/dotnet/csharplang/issues/406
|
|
|
|
#### Diamond inheritance
|
|
|
|
We've come down to two options: pick an implementation somewhat arbitrarily,
|
|
or produce a runtime exception. The positive about picking one is that we
|
|
more strongly provide the guarantee that adding a default method
|
|
implementation will not "break" the application. The minus is that there's no
|
|
guarantee that the method we actually picked is the correct one.
|
|
|
|
It's also noted that adding a virtual method to a base class can implement an
|
|
interface in the derived class, but you can get the same result just through
|
|
current language behavior:
|
|
|
|
```C#
|
|
interface IFoo { void M() { impl; } }
|
|
class Derived : Base, IFoo {}
|
|
|
|
class Base : Base0
|
|
{
|
|
public virtual void M() {} // added later
|
|
}
|
|
|
|
class Base0 : IFoo
|
|
{
|
|
void IFoo.M() { }
|
|
}
|
|
```
|
|
|
|
**Conclusion**
|
|
|
|
We're going to throw a runtime exception (we want a new exception type) when
|
|
there is a runtime diamond and there is no unique most derived
|
|
implementation. We've decided that the exception will be thrown at method
|
|
resolution time, so the exception would be thrown when taking a delegate to
|
|
the target method, rather than when the delegate is invoked. We should note
|
|
in documentation when this kind of change could be a source or binary
|
|
breaking change.
|
|
|
|
We'd like to have some method to provide static verification, as long as we
|
|
can provide a tool that has access to the runtime environment (like the IL
|
|
linker).
|
|
|
|
#### Permit partial in interface?
|
|
|
|
Partial methods, in addition to the partial type?
|
|
|
|
**Conclusion**
|
|
|
|
Yes, with the same restrictions as in classes.
|
|
|
|
#### `Main` in an interface?
|
|
|
|
No reason why not.
|
|
|
|
#### Confirm that we support public non-virtual methods
|
|
|
|
Yes, we'll support it.
|
|
|
|
#### Does an `override` in an interface introduce a new member?
|
|
|
|
No override keyword in interfaces. This should resolve all listed questions.
|
|
|
|
#### Properties with a private accessor
|
|
|
|
We say that private members are not virtual, and the combination of virtual and private is disallowed. But what about a property with a private accessor?
|
|
|
|
``` c#
|
|
interface IA
|
|
{
|
|
public virtual int P
|
|
{
|
|
get => 3;
|
|
private set => { }
|
|
}
|
|
}
|
|
```
|
|
|
|
Is this allowed? Is the `set` accessor here `virtual` or not? Can it be overridden where it is accessible? Does the following implicitly implement only the `get` accessor?
|
|
|
|
``` c#
|
|
class C : IA
|
|
{
|
|
public int P
|
|
{
|
|
get => 4;
|
|
set { }
|
|
}
|
|
}
|
|
```
|
|
|
|
Is the following presumably an error because IA.P.set isn't virtual and also because it isn't accessible?
|
|
|
|
``` c#
|
|
class C : IA
|
|
{
|
|
int IA.P
|
|
{
|
|
get => 4;
|
|
set { }
|
|
}
|
|
}
|
|
```
|
|
|
|
The first example looks valid, while the last does not. This is resolved
|
|
analogously to how it already works in C#.
|
|
|
|
#### Warning for struct not implementing default method?
|
|
|
|
This seems like something more suited for an analyzer. It also seems like this
|
|
warning could be noisy, since it would fire even if the default interface method
|
|
is never called and no boxing will ever occur.
|
|
|
|
#### When are interface static constructors run?
|
|
|
|
On the desktop CLR, static methods on interfaces currently run the static
|
|
constructor on entry if it has not already been run. It's proposed that we adopt
|
|
the same behavior for instance methods.
|
|
|
|
**Conclusion**
|
|
|
|
Static constructors are also run on entry to instance methods, if the static
|
|
constructor was not `beforefieldinit`, in which case static constructors are
|
|
run before access to the first static field.
|
|
|
|
### Target-typed new()
|
|
|
|
Can you use new() on anything that has a valid constructor? Like `int`? Or a
|
|
tuple?
|
|
|
|
**Conclusion**
|
|
|
|
Yes.
|