Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I'm in a project where it's pretty much my first time doing all the architecture myself, and I'm running into a frustrating situation. My architecture for forms seems to be correct from a heuristic perspective, but I don't think its implementation is correct.
My architecture is thus:
Base Class: OrderForm
Child Classes: PurchaseOrder, Invoice, Credit
Child Class of PurchaseOrder: StockingOrder
Architecturally this makes sense (to me) because all the child classes are OrderForms ("is a") and a Stocking Order "is a" Purchase Order, just a special kind.
PROBLEM
While coding my StockingOrder class, I've noticed that I've had to Shadow most if not all of the methods I want to use from PurchaseOrder since they conceptually do the same thing but require slightly different implementation functionality. This, of course, smells to me, but I don't know how to fix it. What am I doing wrong? Or is this normal?(!)
Thanks...
It sounds like you might need some virtual methods in PurchaseOrder. Maybe something like the following:
public abstract class OrderForm
{
//orderform members
}
public class PurchaseOrder: OrderForm
{
public void DoSomething()
{
//some logic that can be reused by child classes
DoSomethingElse();
}
protected virtual void DoSomethingElse()
{
//specialized logic
}
}
public class StockingOrder: PurchaseOrder
{
protected override void DoSomethingElse()
{
//specialized logic that makes StockingOrder different than PurchaseOrder
}
}
This should help to reuse more code as you could group the similar logic you are writing in the PurchaseOrder DoSomethingMethod while keepin the specialized logic (that is different between PurchaseOrder and StockingOrder) in your virtual DoSomethingElse method.
As mdearing06 suggested, you should use virtual methods (or just overridable methods) and override them.
Using Shadowing to change the functionality of your own code is somewhat of a bad practice. Shadowing is meant to be used in uncommon scenarios, i.e.: when you inherit from a class that was written by someone else and you must change some of its functionality, but can't view/edit the code itself.
Consider the fact that Shadowing is much like Overloading (only that it hides the base implementations), and quite different than Overriding.
The shadowing method will only be called if you explicitly refer to the object by its class; otherwise, the original method will be called (unlike Overriding, where the method is called based on the content - not on the representation - of the referenced object).
Here is an example of how representation affects a shadowed method's invokation:
Class BaseClass
Public Sub MyMethod()
Trace.WriteLine("The original method")
End Sub
End Class
Class ShadowClass
Inherits BaseClass
Shadows Sub MyMethod()
Trace.WriteLine("The shadowing method")
End Sub
End Class
Class Tester
Public Shared Sub TestClasses()
Dim myObj As Object = New ShadowClass
Dim var0 As BaseClass = myObj
var0.MyMethod()
Dim var1 As ShadowClass = myObj
var1.MyMethod()
End Sub
End Class
After running Tester.TestClasses, the trace will show: "The original method", followed by "The shadowing method".
Now, if we use the following code instead:
Class BaseClass
Public Overridable Sub MyMethod()
Trace.WriteLine("The original method")
End Sub
End Class
Class OverridingClass
Inherits BaseClass
Overrides Sub MyMethod()
Trace.WriteLine("The overriding method")
End Sub
End Class
Class Tester
Public Shared Sub TestClasses()
Dim myObj As Object = New OverridingClass
Dim var0 As BaseClass = myObj
var0.MyMethod()
Dim var1 As OverridingClass = myObj
var1.MyMethod()
End Sub
End Class
The Trace output will display "The overriding method", followed by "The overriding method".
To sum, I'd say that overriding is the "normal" way, and shadowing is an anomaly.
Another option is to use interfaces; set-up code contracts that allow you to program aganist a defined interface without having to worry about the impmentation underneath.
This also allows you to define multiple interfaces that focus on specific tasks, this allows your code to be much more maintainable and flexible.
Then, for common methods, put them in a helper class that your implementations can leverage off.
Check these out for more reference :)
http://www.developer.com/lang/other/article.php/939411/Implementing-Interfaces-in-VB-NET.htm
http://blogs.msdn.com/trobbins/archive/2004/08/26/221241.aspx
Related
So, i want to do what I feel should be such a simple task... pass in a parameter to a constructor using Autofac!
However, I have managed to get a work around working, but just dont think this is correct, I feel i am chaning too much of the recommended code from the Autofac guides
I am more than happy for answers in C# or VB.net it doesnt matter, the location of code is all the same
So, here is my setup (im not fussed about neatness, just trying to get this to work for now)
In my global.asax I have:
'***Note, the autofac guide had this a a private shared, see below for why i changed it***
' Provider that holds the application container.
Public Shared _containerProvider As IContainerProvider
' Instance property that will be used by Autofac HttpModules
' to resolve And inject dependencies.
Public ReadOnly Property ContainerProvider As IContainerProvider Implements IContainerProviderAccessor.ContainerProvider
Get
Return _containerProvider
End Get
End Property
then within my global.asax within application_start I have:
***again, note, originally I was using IMyClass when registering type... not sure this or that is correct***
Dim builder As New ContainerBuilder()
builder.RegisterType(Of MyClass)().As(Of MyClass)().InstancePerLifetimeScope()
'... continue registering dependencies...
' Once you're done registering things, set the container
' provider up with your registrations.
_containerProvider = New ContainerProvider(builder.Build())
As you can see, origianly the _containerProvider was just public, but I have had to make it "Shared" for this to work, this feels wrong right away!
so, now, in my webForm1.aspx.vb I have this:
Public Property MyClass2 As IMyClass
Private _myClass As IMyClass
Now, because I have adjusted the global to "registerType" to use the actual object, not the interface (which, again seems wrong having to change that too), means now my webform public property is not being set (but, because of my work around, i dont need that anyway)
Also, note the private _myClass... this is for my workaround
so, now in my Webform init method, i have the following:
WebForm1.aspx.vb*
_myClass = [Global]._containerProvider.RequestLifetime.Resolve(Of MyClass)(New TypedParameter(GetType(HttpRequest), Request))
which now instantiates my _myClass with the parameter correctly injected in... this is great, whoopadeedoo
...but... I dont think this is correct.
Now, when I didnt need to pass in a parameter to the construtor, it all worked nice, didnt need to change any of the code from the autofac guide, it just worked, set the public property on my webform.aspx page fine, was really nice.
But, as soon as I start to work with a paramter being passed into the construtor, it seems everything needs to be tweaked so it will work? is this correct?
I have even tried the deligate guide from autofac, but that also doesnt work for me at all by doing this within my webForm.aspx page:
Dim container As ILifetimeScope = [Global]._containerProvider.RequestLifetime
Dim myClassFactory As MyClass = container.Resolve(Of MyClass.Factory)
Dim myClassholding As MyClass = myClassFactory.Invoke("ABC")
even tried without the "Invoke", but "cannot be indexed because it has no default property"
Just incase it helps, here is "myClass"
Private _myID as integer
Public Delegate Sub Factory(myID As integer)
Sub New()
End Sub
Sub New(myID As integer)
_myID = myID
End Sub
Public Sub DoSomething() Implements IDfCookieManager.DoSomething
'do something with myID
End Sub
I know I can pass the id in as a parameter to DoSomething, but i want to understand how to pass this into the constructor
so, my questions:
If this is not how to do this (which I am hoping its not correct), how would I do this without needing to change all the global setup??
Is it best to use a deligate factory or just resolve?
do I really need to change the global container to be shared/static, so that i can access the container from within my code?
So, there are two ways, but firstly, shouldnt need to mess around with how Autofac suggests setting up the ContainerProvider in global.asax... i can keep it as non shared (not static), and to access this value I do the following:
Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Also, in our webform.aspx page, Public Property MyClass As IMyClass should not be added when we need to pass in parameters to the constructor when resolving (otherwise it will be resolved before we try to manually resolve it!
1: Passing in using TypedParameter
Here is my adjusted code to pass in the parameters using resolve (including the lines above):
Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Dim myClass As MyClass = scope.Resolve(Of IMyClass)(New TypedParameter(GetType(Integer), 123))
Also, having the public property at the top of my WebForm1.aspx needed to be removed, because that will auto resolve, meaning, if i try to "resolve" the object manually, it has already been automatically resolved by autofac (which is why i thought my code wasnt working initially), and has already instantiated the object with the empty constructor!
2: Using a Deligate Factory
the line Public Delegate Sub Factory(myID As integer) isnt correct, it should use a function for Autofac to automaticly set this up! so should be: Public Delegate Function Factory(myID As integer) as MyClass
In Global.asax, I just need to add this builder.RegisterType(Of MyClass)().InstancePerLifetimeScope(), because we require a parameter and using a factory, we cant append the .As(Of IMyClass)
Finally, our webform1.aspx.vb just needs this:
Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Dim myClassFactory As MyClass.Factory = scope.Resolve(Of MyClass.Factory)
_myClass = myClassFactory.Invoke(123)
however, I tweaked that slightly to this:
Dim cpa As IContainerProviderAccessor = (CType(HttpContext.Current.ApplicationInstance, IContainerProviderAccessor))
Dim scope As ILifetimeScope = cpa.ContainerProvider.RequestLifetime
Dim myClass As MyClass = scope.Resolve(Of MyClass.Factory).Invoke(123)
I created a simple solution with an EDMX file that possess one table Sport with 2 field IdSport and Label. I would like to insert a record in DB with an object inherited of the Sport object created by EF.
Public Class Index
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim aSport As New TestSport()
Using ctx As New FormationEntities
ctx.AddObject("Sport", aSport)
ctx.SaveChanges()
End Using
End Sub
End Class
Public Class TestSport
Inherits Sport
End Class
With an Sport object it work but not with TestSport. I need the inherited class for adding some properties and others functionnalities, but when I save it, I would like to save only the property possessed by the parent object Sport.
Error message:
Mapping and metadata information could not be found for EntityType
I know that the usual way is to use partial class but on my project, the EDMX file is in another project, so the only solution I see is to use an inherited class.
What am I doing wrong? How to fix my problem? Is it exist a better way to do it?
Thanks.
On searching through gooogle I found the following link, where a very similar scenario is discussed:
Deriving from classes generated by Entity Framework in C#
Although there is one post marked as answer, but the second answer is equally relevant.
Hope this helps.
Entity Framework appears to use a kind of reflection during the saving of your entities, and is probably why your inheritances do not work. One way you could still add functionality to your enties(albeit only functions) is using Extension methods: http://msdn.microsoft.com/en-us//library/bb383977.aspx
But if it is more than just some functions you need to add, consider a more structural solution. Having part of your object in a data layer and part of that same object in an upper layer is not a good separation of responsibilities.
Instead of having part of the class in your data project(I assume), and part of it in another project, consider creating one 'Logics class' in your project which wraps around your entity and adds functionality that way. You could for example do this by exposing the entity directly:
public class SportLogic
{
private Sport _sport;
public Sport Sport { get { return _sport; } }
public string SomeNewProperty { get; set; }
public void DoStuff() {};
}
Or the way I use where the logics object is acting as an actual logical wrapper around the entity. It is cleaner because it obfuscates the entity entirely: any calling code wil not need knowledge of your entity(Sport) object.
public class SportLogic
{
private Sport _sport;
public string SportProperty { get { return _sport.SportProperty; } set { _sport.SportProperty = value; } }
public string SomeNewProperty { get; set; }
public void DoStuff() {};
}
I asked this question several weeks ago and received some good answers: ASP.NET Class Library best practice. I now have another question.
The problem I have is that I have inherited an ASP.NET application, which contains lots of classes with tight coupling and low cohesion, which is not ideal. I want to share some of the code with other apps. Most of the code exists in one class, however the class references other classes and those classes reference other classes etc. Is there any way of sharing the code in one class (which references other classes)? The only way I can think of doing this is using web services, but there is sensitive information.
The only good option, in cases like this, is refactoring the code. You don't have to change the existing class interface, however. You can create multiple new classes that are designed properly and replace the logic in the original poorly designed class. Then you can refactor the original class to use the new classes internally to perform the functionality. You don't have to do this all at once. As you find that you need a particular bit of logic in a shared library, just refactor that logic and leave the rest untouched. Over time you can, in this way, refactor the whole thing. Unless, of course, it's not that big or you have all the time in the world to refactor the beast. However, usually that's not the case.
For instance, let's say you have the following overly simplified classes:
Public Class OriginalBeast
Private _dependency As New Dependency()
Public Function Method1() As Integer
Return _dependency.Calculate(2)
End Sub
Public Function Method2() As Integer
Return _dependency.Calculate(2)
End Sub
' ...
Public Function Method1027() As Integer
Return _dependency.Calculate(1027)
End Sub
End Class
Public Class Dependency
Public Function Calculate(value As Integer) As Integer
Return value * 2
End Function
End Class
And you want to share the logic in OriginalBeast.Method2 in a class library, you would need to move the Dependency class to the class library (and likely need to partially refactor it as well). Then you would need to create a new class that contains just the desired methods from the original beast:
Public Interface INice
Function Method2() As Integer
End Interface
Public Class Nice
Implements INice
Public Sub New(dependency As IDependency)
_dependency = dependency
End Sub
Private _dependency As IDependency
Public Function Method2() As Integer Implements INice.Method2
Return _dependency.Calculate(2)
End Function
End Class
Public Interface IDependency
Function Calculate(value As Integer) As Integer
End Interface
Public Class Dependency
Implements IDependency
Public Function Calculate(value As Integer) As Integer Implements IDependency.Calculate
Return value * 2
End Function
End Class
Then, you would need to refactor the original beast to use the class library instead of doing the logic itself:
Public Class OriginalBeast
Public Sub New()
_dependency = New Dependency()
_nice = New Nice(_dependency)
End Sub
Private _dependency As IDependency
Private _nice As INice
Public Function Method1() As Integer
Return _dependency.Calculate(2)
End Sub
Public Function Method2() As Integer
Return _nice.Method2()
End Sub
' ...
Public Function Method1027() As Integer
Return _dependency.Calculate(1027)
End Sub
End Class
Obviously real-world beasts are never that simple and it will likely require a lot of work to refactor even a small part of it, but hopefully that gives you an idea of what I'm talking about.
Maybe I should just make this a public member, but I keep thinking it should be a constant.
SCENARIO
I have forms I'm rendering into PDFs (using iTextSharp). In code, the forms themselves all inherit a base class (OrderForm). Within OrderForm, there are a list of constants that I use for measurements when aligning things for the PDF rendering, such as LEFT_MARGIN, etc. These constants are used in several functions to determine where things go.
All the forms are virtually identical as they are comprised of the same components (header, address boxes, items, etc). However, the layout of the forms differ slightly... on one form, the address box is an inch further to the right (to fit in the envelope window my employer uses).
ISSUE
Rather than create a slew of constants for each margin, padding, blah blah for each form in the base class, eg: PURCHASE_ORDER_LEFT_MARGIN, INVOICE_LEFT_MARGIN, etc, wouldn't it be better to create an overridable LEFT_MARGIN that can be set in the "inheritee" [sic] object? My reasoning is that it is a constant that will not change within that object, only form to form, yet the renderings in the base class will remain relative to whatever that constant is.
I know I could simply create a public member and set its value, but I'd like to know the right way to go about this.
Thanks.
Constants are implicitly static (Shared).
Use a Readonly Property instead, and then you can choose to override it whenever or wherever need be.
A quick example ....
Class BaseClass
' Assume this field is set with a value from somewhere else'
Private _leftmargin As Integer
Overridable Readonly Property LEFT_MARGIN As Integer
Get
Return _leftmargin
End Get
End Property
End Class
Class DerivedClass1
Inherits BaseClass
Overrides Readonly Property LEFT_MARGIN As Integer
Get
Return 5 'specialized case for this class'
End Get
End Property
End Class
Class DerivedClass2
Inherits BaseClass
'uses base class LEFT_MARGIN'
End Class
Constants are compiled as literal values. If you have this (C#) source code:
public static class MyStringTestClass
{
// Fields
public const string ConstString = "Const String";
public void TestMethod()
{
string sc = MyStringTestClass.ConstString;
SomeOtherFunction(sc);
}
}
then the compiler will produce this:
public static class MyStringTestClass
{
// I'm not 100% sure if this declaration is removed as well...
public const string ConstString = "Const String";
public void TestMethod()
{
// ...but I know for sure that it will be removed
// everywhere it's used - including other assemblies!
string sc = "Const String";
SomeOtherFunction(sc);
}
}
As you see, "ConstString" is completely GONE and it's literal value is inserted everywhere.
So use the VB.net equivalent of a ReadOnly Virtual Property (I think "virtual" is called "Overridable" in VB.net?) and override it.
What you want is a regular property ... Any value that changes is not a constant ... :)
What you can do is to use methods instead of constants. At the base class the method will return the value of the constant as it is now.
Inheriting class can provide a new value for the "constant" by overriding the corresponding method.
am trying to implement fluent nhibernate in MVC project...there were no build errors... but when i run the project i get this exception
System.Xml.Schema.XmlSchemaValidationException: The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has incomplete content. List of possible elements expected: 'meta, subselect, cache, synchronize, comment, tuplizer, id, composite-id' in namespace 'urn:nhibernate-mapping-2.2'.
have no idea what am doing wrong here... the following is the code for opening session factory...
Private Function CreateSessionFactory() As ISessionFactory
Dim sessionFactoryObject As ISessionFactory
sessionFactoryObject = Fluently.Configure().Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005.ConnectionString("Data Source=.\sqlexpress;Initial Catalog=Designs;User ID=sa;Password=root")).Mappings(Function(x) x.FluentMappings.Add(GetType(DesignMap))).BuildSessionFactory()
Return sessionFactoryObject
End Function
this is really driving me nuts....thanks in advance...:)
update-the mappings
the design table map
Public Class DesignMap
Inherits ClassMap(Of Design)
Public Sub DesignMap()
Table("DesignList")
Id(Function(x) x.DesignId)
Map(Function(x) x.DesignType)
References(Function(x) x.Designer, "DesignerId")
End Sub
End Class
the designer table map
Public Class DesignerMap
Inherits ClassMap(Of Designer)
Public Sub DesignerMap()
Table("DesignerList")
Id(Function(x) x.DesignerId)
Map(Function(x) x.DesignerName)
Map(Function(x) x.DesignerCompany)
HasMany(Function(x) x.DesignersDesigns)
End Sub
End Class
new edit-- the entity property looks like this
Public Overridable Property Name() As String
Get
Return _name
End Get
Protected Set(ByVal value As String)
_name = value
End Set
End Property
am i going the right way..?
I'm not quite sure as the mappings seem ok. I can see one error tough, you have only mapped one of your classes:
.Mappings(Function(x) x.FluentMappings.Add(GetType(DesignMap)))
That should not cause this type of error tough. If you add both your mappings and call the method .ExportTo(#"C:\your\export\path") you will get the actual xml mappings. This way it's easier to see the error. You can do that like this:
.Mappings(Function(x) x.FluentMappings.Add(GetType(DesignMap)).Add(GetType(DesignerMap
).ExportTo(#"C:\your\export\path"))
You can also use the method AddFromAssemblyOf (or some other. There is a few choices) if you don't want to add the mappings one by one.
Try exporting the mappings and see if you can find any error. Or you can post the xml mappings and someone else might find something.
There are several things that can cause this. When using automappings, you will get this if you incorrectly specify the assemblies and namespaces to look in. Other things (more likely in your case) that could cause it, are entity properties that aren't marked as public virtual, having an entity constructor with arguments, but neglecting to make a default constructor, or inheriting your entities from a base class.
I would probably first check to make sure all of your entity properties are "public virtual".
found the problem...the constructor for the map was wrong...it should be like this...
Public Class DesignMap
Inherits ClassMap(Of Design)
Public Sub New()
Table("DesignList")
Id(Function(x) x.DesignId)
Map(Function(x) x.DesignType)
References(Function(x) x.Designer, "DesignerId")
End Sub
End Class
problems of working in both C# and vb.net at the same time i guess..!!
and "Matthew Talbert" was correct...making all the properties Overrideable is important..
thanks guys...:)