then the new student submits their answer to ...
-
write a c# 8 Core 7 example of InterFace and Abstract class:
namespace _07_08_2023_test
{
public interface IFace1
{
DateTime DTimeUTC { get; }
}public interface IFace2 { string FirstName { get; } string LastName { get; } } public abstract class Abs1 : IFace1, IFace2 { public DateTime DTimeUTC {get; } = DateTime.Now.ToUniversalTime(); public string FirstName { get; protected set; } public string LastName { get; protected set; } public string FullName { get => $"{FirstName} ... {LastName}"; } } public class StudentMess : Abs1 { public StudentMess(string fname, string lname) { FirstName = fname; LastName = lname; } }
}
And, said new student says: "it compiles, and I can do this:"
private void Form1\_Load(object sender, EventArgs e) { StudentMess smess = new StudentMess("new", "confused"); }
And, you shake your head.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
-
write a c# 8 Core 7 example of InterFace and Abstract class:
namespace _07_08_2023_test
{
public interface IFace1
{
DateTime DTimeUTC { get; }
}public interface IFace2 { string FirstName { get; } string LastName { get; } } public abstract class Abs1 : IFace1, IFace2 { public DateTime DTimeUTC {get; } = DateTime.Now.ToUniversalTime(); public string FirstName { get; protected set; } public string LastName { get; protected set; } public string FullName { get => $"{FirstName} ... {LastName}"; } } public class StudentMess : Abs1 { public StudentMess(string fname, string lname) { FirstName = fname; LastName = lname; } }
}
And, said new student says: "it compiles, and I can do this:"
private void Form1\_Load(object sender, EventArgs e) { StudentMess smess = new StudentMess("new", "confused"); }
And, you shake your head.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
Judging by your message here, and earlier posts, I guess that you're trying to figure out what problem is being solved by the new interface implementations capability being introduced in the language now. Would that be fair to say? If so, you aren't actually using that capability in your example. What am I missing here? -- edited to add the word using
-
Judging by your message here, and earlier posts, I guess that you're trying to figure out what problem is being solved by the new interface implementations capability being introduced in the language now. Would that be fair to say? If so, you aren't actually using that capability in your example. What am I missing here? -- edited to add the word using
Pete O'Hanlon wrote:
what problem is being solved by the new interface implementations capability being introduced in the language now.
Thanks, Pete Yes, i am asking what advantages are being offered to make what, imho, is a classic pillar of modern programming a different construct.
Pete O'Hanlon wrote:
What am I missing here?
i guess my "student mess" example did not convey the difficulty in getting a strategic sense of when to use Interface and Abstract. bill is missing many things right now, including (too often) ability to concentrate, i apologize for my lack of thoroughness.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
-
Judging by your message here, and earlier posts, I guess that you're trying to figure out what problem is being solved by the new interface implementations capability being introduced in the language now. Would that be fair to say? If so, you aren't actually using that capability in your example. What am I missing here? -- edited to add the word using
using C# 8 new Interface features:
public interface IExampleInterface
{
// A method with a default implementation
void DefaultMethod()
{
Console.WriteLine("This is the default implementation of DefaultMethod.");
}// A static method static void StaticMethod() { Console.WriteLine("This is a static method in an interface."); }
}
And ... in C#9: Init-only setters; Target-typed new expressions ... in C#10: Record structs. imho, Interface is becoming very different, and learning the strategic use of the new features much more difficult.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
-
using C# 8 new Interface features:
public interface IExampleInterface
{
// A method with a default implementation
void DefaultMethod()
{
Console.WriteLine("This is the default implementation of DefaultMethod.");
}// A static method static void StaticMethod() { Console.WriteLine("This is a static method in an interface."); }
}
And ... in C#9: Init-only setters; Target-typed new expressions ... in C#10: Record structs. imho, Interface is becoming very different, and learning the strategic use of the new features much more difficult.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
-
using C# 8 new Interface features:
public interface IExampleInterface
{
// A method with a default implementation
void DefaultMethod()
{
Console.WriteLine("This is the default implementation of DefaultMethod.");
}// A static method static void StaticMethod() { Console.WriteLine("This is a static method in an interface."); }
}
And ... in C#9: Init-only setters; Target-typed new expressions ... in C#10: Record structs. imho, Interface is becoming very different, and learning the strategic use of the new features much more difficult.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
Just to make things more confusing, a static interface member with a default implementation must be marked as
virtual
, otherwise you'll get a compiler error when you try to use it:public interface IFoo
{
static void S() => Console.WriteLine("Default");
}static void Test() where T : IFoo
{
// CS0704 Cannot do non-virtual member lookup in 'T' because it is a type parameter
T.S();
}If you don't provide a default implementation, you have to mark it as
abstract
. In order to provide its own implementation, a class has to declare the method aspublic
, which doesn't match the interface declaration, leading to more confusion:public interface IFoo
{
static virtual void S() => Console.WriteLine("Default");
}public class Foo : IFoo
{
// Why is this never called?
static void S() => Console.WriteLine("Overridden");
}static void Test() where T : IFoo
{
T.S();
}Test(); // Output: "Default"
You can alleviate that by marking the interface method as
public
:public interface IFoo
{
public static virtual void S() => Console.WriteLine("Default");
}But IMO, adding access modifiers to interface members goes against the "ethos" of interfaces. If I can see the interface, then I should be able to access all members of that interface, so they shouldn't need to be marked as
public
. And having some membersprotected
orprivate
just seems like nonsense! And if that's still not confusing enough, the implementation of the static method cannot use theoverride
modifier, even though it's required when you provide an implementation of avirtual
/abstract
method from a base class:public class Foo : IFoo
{
// CS0112 A static member cannot be marked as 'override'
public static override void StaticMethod() => Console.WriteLine("Overridden");
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Pete O'Hanlon wrote:
what problem is being solved by the new interface implementations capability being introduced in the language now.
Thanks, Pete Yes, i am asking what advantages are being offered to make what, imho, is a classic pillar of modern programming a different construct.
Pete O'Hanlon wrote:
What am I missing here?
i guess my "student mess" example did not convey the difficulty in getting a strategic sense of when to use Interface and Abstract. bill is missing many things right now, including (too often) ability to concentrate, i apologize for my lack of thoroughness.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
So, the biggest advantage of the interface implementation is that it allows you to add features to an interface without breaking existing implementations. Imagine that you have the following interface:
public interface MyRestApi
{
string ApiName { get; set; }
int Version { get; set; }
string RequestBody { get; set; }
}Now, as an application API author, you have published this interface and your component uses it quite successfully; more importantly, you have shipped this out and 1/4 million happy customers are using your component and are supplying their own implementations of this API into your component. Let's say that you have decided that you want to upgrade your component and add a new feature to this interface; you have decided that it will support a check-sum. You don't want to upset those customers who are already using your component by breaking their build by adding a new property they have to supply. You don't want to stop those customers from having to change their code to use a version 2 of this API; which could be significant disruption. Finally, you want the customers to be able to use your upgraded capability, and adjust to supplying their own checksum implementation when they are ready. That's what this capability provides; you can upgrade the interface by supplying your own default implementation, satisfying the ability not to break things, and the consumer can upgrade the implementation if they want to later on. So, the next version of your component has this interface
public interface MyRestApi
{
string ApiName { get; set; }
int Version { get; set; }
string RequestBody { get; set; }
uint Checksum()
{
using CRC32 crc32 = new();
byte[] data = Encoding.UTF8.GetBytes(RequestBody);
byte[] hashBytes = crc32.ComputeHash(data);
return BitConverter.ToUInt32(hashBytes, 0);
}}
Now, I've just typed this code into the text window here so it may not be 100% correct, but this is one of the reasons for this capability.
-
Just to make things more confusing, a static interface member with a default implementation must be marked as
virtual
, otherwise you'll get a compiler error when you try to use it:public interface IFoo
{
static void S() => Console.WriteLine("Default");
}static void Test() where T : IFoo
{
// CS0704 Cannot do non-virtual member lookup in 'T' because it is a type parameter
T.S();
}If you don't provide a default implementation, you have to mark it as
abstract
. In order to provide its own implementation, a class has to declare the method aspublic
, which doesn't match the interface declaration, leading to more confusion:public interface IFoo
{
static virtual void S() => Console.WriteLine("Default");
}public class Foo : IFoo
{
// Why is this never called?
static void S() => Console.WriteLine("Overridden");
}static void Test() where T : IFoo
{
T.S();
}Test(); // Output: "Default"
You can alleviate that by marking the interface method as
public
:public interface IFoo
{
public static virtual void S() => Console.WriteLine("Default");
}But IMO, adding access modifiers to interface members goes against the "ethos" of interfaces. If I can see the interface, then I should be able to access all members of that interface, so they shouldn't need to be marked as
public
. And having some membersprotected
orprivate
just seems like nonsense! And if that's still not confusing enough, the implementation of the static method cannot use theoverride
modifier, even though it's required when you provide an implementation of avirtual
/abstract
method from a base class:public class Foo : IFoo
{
// CS0112 A static member cannot be marked as 'override'
public static override void StaticMethod() => Console.WriteLine("Overridden");
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Richard Deeming wrote:
adding access modifiers to interface members goes against the "ethos" of interfaces.
"ethos" ... right word ! i am curious which versions of future C#/.NET your thorough review of future "features" are based on ... aside: i am still hung-up on the fact that C# inner classes within outer classes "mean nothing" ... unless, of course you want to make them private and only use/manipulate then from within their containing classes ... i am probably still in recovery from 'Self in SmallTalk, "super" in Java ... my problem ! cheers, bill `
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
-
Richard Deeming wrote:
adding access modifiers to interface members goes against the "ethos" of interfaces.
"ethos" ... right word ! i am curious which versions of future C#/.NET your thorough review of future "features" are based on ... aside: i am still hung-up on the fact that C# inner classes within outer classes "mean nothing" ... unless, of course you want to make them private and only use/manipulate then from within their containing classes ... i am probably still in recovery from 'Self in SmallTalk, "super" in Java ... my problem ! cheers, bill `
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
BillWoodruff wrote:
i am curious which versions of future C#/.NET your thorough review of future "features" are based on ...
Static interface methods were added in preview mode for C# 10, and released with C# 11: Preview Features in .NET 6 - Generic Math - .NET Blog[^] Explore static virtual members in interfaces | Microsoft Learn[^] Default interface implementations were added in C# 8: Default interface methods - C# 8.0 draft feature specifications | Microsoft Learn[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Richard Deeming wrote:
adding access modifiers to interface members goes against the "ethos" of interfaces.
"ethos" ... right word ! i am curious which versions of future C#/.NET your thorough review of future "features" are based on ... aside: i am still hung-up on the fact that C# inner classes within outer classes "mean nothing" ... unless, of course you want to make them private and only use/manipulate then from within their containing classes ... i am probably still in recovery from 'Self in SmallTalk, "super" in Java ... my problem ! cheers, bill `
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
Some more confusion for you from Reddit, relating to the older default interface implementation rather than the newer static interface members:
https://www.reddit.com/r/csharp/comments/15o30l1/explicit_interface_reabstraction/[^]:
I had a question while reading the Microsoft docs on interfaces https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#reabstraction[^] In the docs, they give the example
interface IA
{
void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
abstract void IA.M();
}
class C : IB { } // error: class 'C' does not implement 'IA.M'.Which forces you to implement method
M
in classC
. However, you can also define the interfaceIB
this way, which also forces methodM
to be defined in classC
.interface IA
{
void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
new void M();
}
class C : IB { } // error: class 'C' does not implement 'IB.M'.I did notice there is a small difference, where since in the second example, interface IB is shadowing IA, the error message changes, but in practice, is there any difference between these two?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Some more confusion for you from Reddit, relating to the older default interface implementation rather than the newer static interface members:
https://www.reddit.com/r/csharp/comments/15o30l1/explicit_interface_reabstraction/[^]:
I had a question while reading the Microsoft docs on interfaces https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#reabstraction[^] In the docs, they give the example
interface IA
{
void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
abstract void IA.M();
}
class C : IB { } // error: class 'C' does not implement 'IA.M'.Which forces you to implement method
M
in classC
. However, you can also define the interfaceIB
this way, which also forces methodM
to be defined in classC
.interface IA
{
void M() { WriteLine("IA.M"); }
}
interface IB : IA
{
new void M();
}
class C : IB { } // error: class 'C' does not implement 'IB.M'.I did notice there is a small difference, where since in the second example, interface IB is shadowing IA, the error message changes, but in practice, is there any difference between these two?
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
I would prefer the second one as it completely hides IA from C (which mostly I would want when I setting up like this). This also suggests me that the 1st implementation is for scenarios where you don't want to hide and be much more explicit about who is asking to implement (also IB is mostly playing middlemen for some reason known/unknown).
Latest CodeProject post: Quick look into Machine Learning workflow How to solve Word Ladder Problem? To read all my blog posts, visit: Learn by Insight...