Partial methods and inheritance from non-partial classes - c#

I imported a table from the database using designer, then I've edited the corresponding cs file to add extra functionality to the model (it's a partial exactly for this reason). Now I came up with some ideas on how to make that functionality more reusable and packed that into a base class (so in the context code I have partial class Foo : BaseClass). I made the partial class inherit the base class and all is fine... except for partial methods.
The generated partial class has some partial methods that normally don't have any code (namely the OnCreated method). I've added an OnCreated method to the base class and put a breakpoint in it, but it's never hit.
Can I somehow make a partial class take the code for partial method from a non-partial parent or am I doing something wrong here?
Background: I have a certain structure (columns containing author's id, id of user who was the last one to modify the record and dates of create and update dates) that is appearing in multiple tables and I'm trying to define most code for handling that in a single place in my project. It involves having uniform access to associated users and I had some luck doing that by defining associations in my base class (basically this, but with few modifications). So far it appears to works perfectly, except for the fact that I should be assigning default values to storage variables inside of the constructor of the generated class
(this._SomeVariable = default(EntityRef<SomeModel>)). However modifying the generated code is pointless, since all changes will be lost when the file is generated anew. So the next best thing would be to implement OnCreated partial method which is run at the end of the generated class. I can implement that in the non-generated cs file for my model, but I'd rather put it inside the base class which is shared with all similar models.
Here is some minimal code to make it more clear:
Generated code:
partial class Foo
{
public Foo()
{
// does some initialization here
this.OnCreated();
}
partial void OnCreated();
}
Extended code for Foo:
partial class Foo : BaseClass // Thanks to this I can use the uniform JustSomeModel association
{
// This code here would run if it was uncommented
// partial void OnCreated() {}
// However I'd rather just have the code from base.OnCreated()
// run without explicitly calling it
}
Base class:
public class BaseClass
{
protected EntityRef<SomeModel> _SomeVariable;
[Association(Name = "FK_SomeModel", Storage = "_SomeVariable", ThisKey = "SomeModelId", OtherKey = "Id", IsForeignKey = true)]
public SomeMode JustSomeModel
{
get
{
return this._SomeVariable.Entity;
}
}
// This never runs
public void OnCreated()
{
this._SomeVariable = default(EntityRef<SomeModel>)
}
}
The best solution I can think of right now would be to do this:
partial class Foo : BaseClass
{
partial void OnCreated()
{
base.OnCreated(); // Haven't really tested this yet
}
}
However this means I will have to add this piece of code to every model inheriting from BaseClass that I use and I'd rather avoid it.

Based on information posted by Eugene Podskal I can assume this cannot be done and my best bet is implementing the partial method and calling base method inside it.
partial class Foo : BaseClass
{
partial void OnCreated()
{
base.OnCreated();
}
}
Edit: Tested it and it works.

Related

Modifying / Adding to C# Partial Classes

I have got a partial class in my C# project i.e. auto-generated code from Entity Framework. Now I want to modify or add some more functionalities, properties or methods to that class. I have the auto-generated class code under EntityFrameworkModel.tt\Author.cs tab in the project while the other related classes are in another folder i.e. GraphData in the same project.
I also know that the name of partial classes should be same while file name may be different or same as well. I did same but when I defined the object for Author.cs as:
protected override EvoObject ConvertCPV(Author _author)
{
if (_author.???)
{
//...
}
}
I can't access the methods defined in GraphData\Author.cs (The question marks in example code) whereas the properties defined in EntityFrameworkModel.tt\Author.cs are only accessible.
Here I attached the Solution Explorer image as:
How can I access the properties and methods from both classes?
I have a similar set up in a project also.
To keep things tidy I also have folders where I place certain partial classes, you just need to ensure the namespace is the same as the auto generated class.
When you add a new class to a folder the namespace will automatically contain the name of the folder - you can just remove the folder name from the namespace - you should just have the Project name in this scenario.
If the namespaces are different then the partial classes are not part of the same class. This is why you can't access the new functions/Properties.
Also, even though your file name and class names can be different, it is better to keep them the same - it will be easier to find a class if the file has the same name.
Check out https://msdn.microsoft.com/en-us/library/wa80x488.aspx
It says "The partial keyword indicates that other parts of the class, struct, or interface can be defined in the namespace." It does not explicitly state this, but that implies that the partial definitions of the class must be declared in the same namespace. It doesn't matter which files in the project contain the classes, or what folders they are in.
using System;
namespace DemoConsoleApp
{
class Program
{
static void Main(string[] args)
{
SameNamespace.PartialClass.MethodOne();
SameNamespace.PartialClass.MethodTwo();
DifferentNamespace.PartialClass.MethodThree();
}
}
}
namespace SameNamespace
{
public partial class PartialClass
{
public static void MethodOne()
{
Console.WriteLine("Method One.");
}
}
public partial class PartialClass
{
public static void MethodTwo()
{
Console.WriteLine("Method Two.");
}
}
}
namespace DifferentNamespace
{
public partial class PartialClass
{
public static void MethodThree()
{
Console.WriteLine("Method Three.");
}
}
}
Make your own class outside of EntityFrameworkModel.tt - name it Author.cs, make the class partial.
The whole idea of partial is to allow code generators not to care about your code. Of you modify a generated class, the next regeneration kills the changes.
I did same but when I defined the object for Author.cs as:
Ah, no, you did not because then you claim your definition is:
protected override EvoObject ConvertCPV(Author _author)
Which is NOT defining the object.
I can't access the methods defined in GraphData\Author.cs
Because namespace? Check the namespaces - bad to have them in a subfolder when they belong in a the same namespace as EntityFrameworkModel.tt
whereas the properties defined in EntityFrameworkModel.tt\Author.cs are only
accessible.
Partial classes do not allow changes in another partial - not for the moment, a substition syntax is considered.

Polymorphism in WPF

Here's my wish to create something abstract in WPF. You've got a main window (called main for example, even if it's not correct we don't care) with two buttons. Those two buttons have the same function : they open a new window, the same for both of them, but with different things inside. So I decided to create an abstract class to rule them like that :
public abstract (partial ?) class A : Window
{
public A()
{
InitializeComponent(); // Not sure about that, it's kinda weird to use it here no ?
}
...
}
public partial class B : A
{
public B()
{
InitializeComponent(); // Since it's already in A I shouldn't have to use it here right ?
}
...
}
public partial class C : A
{
public C()
{
InitializeComponent(); // Same thing here...
}
...
}
Debugging gives me something like : "error CS0263: Partial declarations of 'namespace.B' must not specify different base classes".
Removing 'partial' from A class gives : "error CS0260: Missing partial modifier on declaration of type 'namespace.A'; another partial declaration of this type exists".
I know that 'partial' specifies if a class has another part of her somewhere else (like the xaml file beside the cs one), so I guess the abstract class has to be partial too since it contains my controls. Maybe the B class shouldn't be partial ?
I know (memories) it works with Windows Forms, but there's no xaml files so it's easier, and I didn't find any useful tips. I think I understood that this problem occurs when I don't change something in my xaml file, which doesn't works as simply as "class : abstract class". Maybe the subclass thing ?
Please note that I'm a beginner in WPF apps, so I thank you in advance if your answer is as detailed as possible.
Thanks !
You need to define your base class all in code without using XAML :
Code for class A :
public abstract class A : Window { }
Code for class B :
public partial class B : A
{
public B()
{
InitializeComponent();
}
}
xaml for class B :
<yourNamespace:A x:Class="yourNamespace.B"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:yourNamespace="clr-namespace:yourNamespace"...
A C# partial class is one that is defined over two or more source files. The other 'part' of Window is generated by Visual Studio, and includes things like InitializeComponent()
If you want a base Window class, then it has to be defined entirely in code, and have no XAML component. It will then no longer be a partial class.
public abstract class WindowA : Window
{
// define base methods here
}
Then you can derive WindowB from WindowA:
public partial class WindowB : WindowA
{
public WindowB()
{
InitializeComponent();
}
}
But you also need to do it in the other 'part', i.e. in XAML, so in WindowB's XAML file, the root Window tag needs to be changed to:
<wpfApp:WindowA x:Class="WpfApp.WindowB"
wpfApp:WindowA ="clr-namespace:WpfApp"
(you'll need to change the namespace appropriately)
This will generate the other 'part' deriving from WindowA, so there will be no inconsistency.
The InitializeComponent() method should be called in each derived class' constructor, as it's specific to that class, i.e. in this case, the other 'part' is generated from the XAML, and defines an InitializeComponent() with resourceLocator code that specific to WindowB.

IntelliSense doesn't show partial class method

I have partial class User generated by LINQtoSQL as shortly following:
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.[User]")]
public partial class User : INotifyPropertyChanging, INotifyPropertyChanged
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
...
Then I created separate folder "Proxy" in my project and put there extra piece of User class:
namespace LINQtoSQL_sample.Proxy
{
public partial class User
{
public static string GetActivationUrl()
{
return Guid.NewGuid().ToString("N");
...
Issue happens when I try to invoke that extra static method from another part of same project. Let's say I have once more folder "SqlRepositoryImpl" and another one partial class there:
namespace LINQtoSQL_sample.SqlRepositoryImpl
{
public partial class SqlRepository
{
public bool CreateUser(User instance)
{
if (instance.ID == 0)
{
instance.added_date = DateTime.Now;
instance.activated_link = LINQtoSQL_sample.Proxy.User.GetActivationUrl();
...
As you can see I explicitly defined which part of User class I'm calling for because IntelliSense didn't suggest me my extra method.
Please, advise why such happens and where I'm wrong?
As you can see I explicitly defined which part of User class I'm calling for because IntelliSense didn't suggest me my extra method.
When you call a method from a class, there are no “parts” of the class anymore.
If you need to (and can) specify the full namespace of the class to invoke a method from it that means you actually have two different classes in two different namespaces. If the two partial declarations are in different namespaces, then you have actually declared two separate classes, not a single class from two parts.

Dividing class file into partial classes affects scope?

I have a class library project, and my namespace/main class looks like this:
File: Document.cs
namespace HtmlEngine
{
public class Document : IDisposable
{ ...
public class DocumentActionReplaceByTag : IDocumentAction
{
All of this works fine, and in another project/assembly I put:
using HtmlEngine;
...
DocumentActionReplaceByTag currentDocAction = new HtmlEngine.DocumentActionReplaceByTag("[NEXT_PART]");
and it works perfectly. However, I've now divided that Document class file into several files, called DocumentActions.cs, DocumentSections.cs, as well as keeping the main functionality in my Document.cs file. At the top of each of these I put:
public partial class Document : IDisposable
{
Now, in the consuming project I get a 'cannot resolve symbol 'DocumentActionReplaceByTag'' error. I still have my using reference to HtmlEngine.
The closest thing on the 'net I could find was this post which describes my plight similarly, but he wasn't very clear about the reasons for it happening: http://www.daniweb.com/software-development/csharp/threads/140673/understanding-partial-classes
I have always believed partial classes were syntactic sugar and they were combined into a single class prior to compilation. I repeated the interface for each partial class declaration, not sure if that could be a factor.
Why would this now be out of scope?
If I understood your code correctrly the line for creating new DocumentActionReplaceByTag must look like:
DocumentActionReplaceByTag currentDocAction = new HtmlEngine.Document.DocumentActionReplaceByTag("[NEXT_PART]");
And what about IDisposable, it must be specified only in one partial file.
Glinkot, from provided code I see that your DocumentActionReplaceByTag class is put into Document class. The folowing sample shows that Nested classes always accessable via ParentClass.NestedClass (note that all my classes are in same file and code not compiles)
namespace SomeNamespace
{
public class ParentClass
{
public class NestedClass { }
public void SomeMethod()
{
// This compiles, since nested class is used inside parent class
NestedClass nestedClass = new NestedClass();
}
}
public class AnotherClass
{
public AnotherClass()
{
// Not compiles since "NestedClass" is defined as nested class
var nestedClass = new NestedClass();
// Will compiles
var nestedClass = new ParentClass.NestedClass();
// Not compiles since "NestedClass" is defined as nested class
NestedClass nestedClass = new NestedClass();
// Will compiles
ParentClass.NestedClass nestedClass = new ParentClass.NestedClass();
}
}
}
If you have another situation then please provide more details.

Override Default Constructor of Partial Class with Another Partial Class

I don't think this is possible, but if is then I need it :)
I have a auto-generated proxy file from the wsdl.exe command line tool by Visual Studio 2008.
The proxy output is partial classes. I want to override the default constructor that is generated. I would rather not modify the code since it is auto-generated.
I tried making another partial class and redefining the default constructor, but that doesn't work. I then tried using the override and new keywords, but that doesn't work.
I know I could inherit from the partial class, but that would mean I'd have to change all of our source code to point to the new parent class. I would rather not have to do this.
Any ideas, work arounds, or hacks?
//Auto-generated class
namespace MyNamespace {
public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol {
public MyWebService() {
string myString = "auto-generated constructor";
//other code...
}
}
}
//Manually created class in order to override the default constructor
namespace MyNamespace {
public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol {
public override MyWebService() { //this doesn't work
string myString = "overridden constructor";
//other code...
}
}
}
I had a similar problem, with my generated code being created by a DBML file (I'm using Linq-to-SQL classes).
In the generated class it calls a partial void called OnCreated() at the end of the constructor.
Long story short, if you want to keep the important constructor stuff the generated class does for you (which you probably should do), then in your partial class create the following:
partial void OnCreated()
{
// Do the extra stuff here;
}
This is not possible.
Partial classes are essentially parts of the same class; no method can be defined twice or overridden, and that includes the constructor.
You could call a method in the constructor, and only implement it in the other part file.
Hmmm,
I think one elegant solution would be the following:
//* AutogenCls.cs file
//* Let say the file is auto-generated ==> it will be overridden each time when
//* auto-generation will be triggered.
//*
//* Auto-generated class, let say via xsd.exe
//*
partial class AutogenCls
{
public AutogenCls(...)
{
}
}
//* AutogenCls_Cunstomization.cs file
//* The file keeps customization code completely separated from
//* auto-generated AutogenCls.cs file.
//*
partial class AutogenCls
{
//* The following line ensures execution at the construction time
MyCustomization m_MyCustomizationInstance = new MyCustomization ();
//* The following inner&private implementation class implements customization.
class MyCustomization
{
MyCustomization ()
{
//* IMPLEMENT HERE WHATEVER YOU WANT TO EXECUTE DURING CONSTRUCTION TIME
}
}
}
This approach has some drawbacks (as everything):
It is not clear when exactly will be executed the constructor of the MyCustomization inner class during whole construction procedure of the AutogenCls class.
If there will be necessary to implement IDiposable interface for the MyCustomization class to correctly handle disposing of unmanaged resources of the MyCustomization class, I don't know (yet) how to trigger the MyCustomization.Dispose() method without touching the AutogenCls.cs file ... (but as I told 'yet' :)
But this approach offers great separation from auto-generated code - whole customization is separated in different src code file.
enjoy :)
Actually, this is now possible, now that partial methods have been added. Here's the doc:
http://msdn.microsoft.com/en-us/library/wa80x488.aspx
Basically, the idea is that you can declare and call a method in one file where you are defining the partial class, but not actually define the method in that file. In the other file, you can then define the method. If you are building an assembly where the method is not defined, then the ORM will remove all calls to the function.
So in the case above it would look like this:
//Auto-generated class
namespace MyNamespace {
public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol {
public MyWebService() {
string myString = "auto-generated constructor";
OtherCode();
}
}
}
partial void OtherCode();
//Manually created class in order to override the default constructor
partial void OtherCode()
{
//do whatever extra stuff you wanted.
}
It is somewhat limited, and in this particular case, where you have a generated file that you'd need to alter, it might not be the right solution, but for others who stumbled on this trying to override functionality in partial classes, this can be quite helpful.
The problem that the OP has got is that the web reference proxy doesn't generate any partial methods that you can use to intercept the constructor.
I ran into the same problem, and I can't just upgrade to WCF because the web service that I'm targetting doesn't support it.
I didn't want to manually amend the autogenerated code because it'll get flattened if anyone ever invokes the code generation.
I tackled the problem from a different angle. I knew my initialization needed doing before a request, it didn't really need to be done at construction time, so I just overrode the GetWebRequest method like so.
protected override WebRequest GetWebRequest(Uri uri)
{
//only perform the initialization once
if (!hasBeenInitialized)
{
Initialize();
}
return base.GetWebRequest(uri);
}
bool hasBeenInitialized = false;
private void Initialize()
{
//do your initialization here...
hasBeenInitialized = true;
}
This is a nice solution because it doesn't involve hacking the auto generated code, and it fits the OP's exact use case of performing initialization login for a SoapHttpClientProtocol auto generated proxy.
You can't do this. I suggest using a partial method which you can then create a definition for. Something like:
public partial class MyClass{
public MyClass(){
... normal construction goes here ...
AfterCreated();
}
public partial void OnCreated();
}
The rest should be pretty self explanatory.
EDIT:
I would also like to point out that you should be defining an interface for this service, which you can then program to, so you don't have to have references to the actual implementation. If you did this then you'd have a few other options.
I am thinking you might be able to do this with PostSharp, and it looks like someone has done just what you want for methods in generated partial classes. I don't know if this will readily translate to the ability to write a method and have its body replace the constructor as I haven't given it a shot yet but it seems worth a shot.
Edit: this is along the same lines and also looks interesting.
Sometimes you don't have access or it's not allowed to change the default constructor, for this reason you cannot have the default constructor to call any methods.
In this case you can create another constructor with a dummy parameter, and make this new constructor to call the default constructor using ": this()"
public SomeClass(int x) : this()
{
//Your extra initialization here
}
And when you create a new instance of this class you just pass dummy parameter like this:
SomeClass objSomeClass = new SomeClass(0);
This is in my opinion a design flaw in the language. They should have allowed multiple implementations of one partial method, that would have provided a nice solution.
In an even nicer way the constructor (also a method) can then also be simply be marked partial and multiple constructors with the same signature would run when creating an object.
The most simple solution is probably to add one partial 'constructor' method per extra partial class:
public partial class MyClass{
public MyClass(){
... normal construction goes here ...
OnCreated1();
OnCreated2();
...
}
public partial void OnCreated1();
public partial void OnCreated2();
}
If you want the partial classes to be agnostic about each other, you can use reflection:
// In MyClassMyAspect1.cs
public partial class MyClass{
public void MyClass_MyAspect2(){
... normal construction goes here ...
}
}
// In MyClassMyAspect2.cs
public partial class MyClass{
public void MyClass_MyAspect1(){
... normal construction goes here ...
}
}
// In MyClassConstructor.cs
public partial class MyClass : IDisposable {
public MyClass(){
GetType().GetMethods().Where(x => x.Name.StartsWith("MyClass"))
.ForEach(x => x.Invoke(null));
}
public void Dispose() {
GetType().GetMethods().Where(x => x.Name.StartsWith("DisposeMyClass"))
.ForEach(x => x.Invoke(null));
}
}
But really they should just add some more language constructs to work with partial classes.
For a Web service proxy generated by Visual Studio, you cannot add your own constructor in the partial class (well you can, but it does not get called). Instead, you can use the [OnDeserialized] attribute (or [OnDeserializing]) to hook in your own code at the point where the web proxy class is instantiated.
using System.Runtime.Serialization;
partial class MyWebService
{
[OnDeserialized]
public void OnDeserialized(StreamingContext context)
{
// your code here
}
}
I'm not quite addressing the OP, but if you happen to be generating classes with the EntityFramework Reverse POCO Generator, there's a partial method called in the constructor which is handy for initializing things you're adding via partial classes on your own...
Generated by tool:
[System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.3.0")]
public partial class Library {
public string City { get; set; }
public Library() {
InitializePartial();
}
partial void InitializePartial();
}
added by you:
public partial class Library {
List<Book> Books { get; set; }
partial void InitializePartial() {
Books = new List<Book>();
}
}
public class Book {
public string Title { get; set; }
}
A bit late to the game, but this is indeed possible. Kind of.
I recently performed the trick below in a code generator of mine, and the result is satisfying. Yes, a dummy argument is required, but it will not cause any major concerns. For consistency, you may want to apply some rules:
Rules
Manually created constructor must be protected.
Generated constructor must be public, with the same arguments as the protected one plus an extra optional dummy argument.
The generated constructor calls the original constructor with all the supplied arguments.
This works for regular construction as well as reflection:
var s1 = new MyWebService();
var s2 = (MyWebService?)Activator.CreateInstance(
typeof(MyWebService),
BindingFlags.CreateInstance | BindingFlags.Public);
And for IoC, it should also work (verified in DryIoc). The container resolves the injected arguments, skipping the optional ones:
var service = container.Resolve<MyWebService>();
Sample code
// <auto-generated />
public partial class MyWebService
{
public MyWebService(object? dummyArgument = default)
: this()
{
// Auto-generated constructor
}
}
// Manually created
public partial class MyWebService
{
protected MyWebService()
{
}
}
The above works for any number of constructor arguments. As for the dummy arguments, we could invent a special type (maybe an enum) further restricting possible abuse of this extra argument.
Nothing that I can think of. The "best" way I can come up with is to add a ctor with a dummy parameter and use that:
public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol
{
public override MyWebService(int dummy)
{
string myString = "overridden constructor";
//other code...
}
}
MyWebService mws = new MyWebService(0);

Categories

Resources