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.
Related
I need to compare the values of two lists of objects in VB.NET in a web application. I can't seem to find any working examples of how to do this.
I have tried the example here: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?view=netframework-4.0
Where they implement a custom interface for doing so. But even using the exact code gives me errors.
Here is the code I'm currently trying. It's basically the same thing as Microsoft's example but using my own class:
Public Class ForumWithName
Inherits IEquatable(Of ForumWithName)
Private mForumID As Integer
Public Property ForumID() As Integer
Get
Return mForumID
End Get
Set(value As Integer)
mForumID = value
End Set
End Property
Private mForumName As String
Public Property ForumName As String
Get
Return mForumName
End Get
Set(value As String)
mForumName = value
End Set
End Property
Private mSubscribed As Boolean
Public Property Subscribed As Boolean
Get
Return mSubscribed
End Get
Set(value As Boolean)
mSubscribed = value
End Set
End Property
Public Function Compare(ByVal other As ForumWithName) As Boolean
If other Is Nothing Then Return False
Return Me.ForumID = other.ForumID AndAlso Me.Subscribed = other.Subscribed
End Function
Public Overrides Function Equals(ByVal obj As Object) As Boolean
Return Compare(TryCast(obj, ForumWithName))
End Function
Public Overrides Function GetHashCode() As Integer
Return (ForumID, Subscribed).GetHashCode()
End Function
End Class
This code fails to compile because of a few errors:
"Classes can inherit only from other classes"
"Predefined type 'ValueTuple(Of,) is not defined or imported."
"Visual Basic 10.0 does not support tuples"
"'GetHashCode' is not a member of '(ForumID as Integer, Subscribed as Boolean)'"
Once I get this code to work, my plan is to compare two lists of the "ForumWithName" class above.
For example(assume SubscribedsForum1 and SubscribedForums2 are both Lists(Of ForumWithName)):
If SubscribedForums1.SequenceEqual(SubscribedForums2) Then
Return True
Else
Return False
End If
IEquatable is an Interface, it needs to be Implemented and not inherited. (I am guessing here, but I think it's a Typo in the MSDN page you linked)
Change the class declare from:
Public Class ForumWithName
Inherits IEquatable(Of ForumWithName)
to be
Public Class ForumWithName
Implements IEquatable(Of ForumWithName)
Once you have done that, you will also need to add this function
Public Overloads Function Equals(other As ForumWithName) As Boolean Implements IEquatable(Of ForumWithName).Equals
Return Compare(TryCast(other, ForumWithName))
End Function
To work around the problem of not being able to use Tuples, you should be able to use this:
Public Overrides Function GetHashCode() As Integer
Return (ForumID & Subscribed).GetHashCode()
End Function
EDIT:
On a side note, you may want to include the properties ForumName and Subscribed in the GetHashCode function to check if the objects are truly equal to one another.
I have the following code:
Public Class Form1
Private Function Step1_Execute() As Boolean
Return Step1_Verify()
End Function
Private Function Step1_Verify() As Boolean
Return True
End Function
Private Function Step2_Execute() As Boolean
Return Step2_Verify()
End Function
Private Function Step2_Verify() As Boolean
Return True
End Function
End Class
What I would like to do is be able to separate the code, similar to the following (which obviously doesn't work):
Public Class Form1
Namespace Step1
Private Function Step1_Execute() As Boolean
Return Step1_Verify()
End Function
Private Function Step1_Verify() As Boolean
Return True
End Function
End Namespace
Namespace Step2
Private Function Step2_Execute() As Boolean
Return Step2_Verify()
End Function
Private Function Step2_Verify() As Boolean
Return True
End Function
End Namespace
End Class
I would like the functionality of namespaces inside of a class, as in something that would let me call Step2.Execute() instead of having to put Step2_ in front of a whole bunch of functions. I don't want to have to create separate classes / modules for step1, step2, etc.
Is there a way that I can accomplish namespace functionality from inside a class?
How about just using a module (equivalent for the most part to a static class in C#)? That would seem to do the job well and give you the reference style you want.
Module Step1
Private Function Execute() As Boolean
Return Verify()
End Function
Private Function Verify() As Boolean
Return True
End Function
End Module
Module Step2
Private Function Execute() As Boolean
Return Step2_Verify()
End Function
Private Function Verify() As Boolean
Return True
End Function
End Module
I believe you can even nest VB.NET Modules within other classes, if you wish.
Edit:
Just realised that all of the modules have the same contract (set of method signatures), so it would actually make sense to implement an interface here, and create instances of the class. A tad more code perhaps, but if you want to abstractify things, it may be worth the effort.
No.
Namespaces are nothing real existing. A namespace is merely a part of the name of a class. So if you have the class System.Text.StringBuilder, the "using System.Text" part is a hint to the compiler like "if you don't find the type, look for all types with the unknown identifier that start with 'System.Text' in front of the unknown part.
Obviously you need to split this up in 3 classes. One that will execute the code. And than 2 that inherit the same interface with an execute and verify method in it.
The executing class wil then contain a collection of this interface and you just add them in the order you wan to execute them.
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
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...:)
I'm looking for a way to write a custom .net class that would allow for nested methods.
For example... say I have a class X with a function Y that returns a list. Then I have another function that returns a sorted list...
I would like to be able to do something like x.y().z() where z would accept the output of y() as its input.
Basically how .toLower() or .toUpper() can be tacked on to any string.
I'm trying to google it but I'm not even sure if I'm asking the right question.
Thanks
Extension methods might be what you are looking for (can accept the output of y()), but that depends on the version of .NET you are using.
so if you wanted to create an extension method called x that takes y as a parameter, you would create a method:
public static object z(input as y)
{
//do your manipulations here
}
so if you wanted your function to do sorting, you would call your sort method, pass the object, y, and return the object sorted.
There's nothing magic which needs to happen. If class A has a method which returns an object of class B, then you can call methods on the function in A directly.
Given:
public static class MyClass
{
public MyList getList()
{
MyList retVal = new MyList();
...
return retVal;
}
}
public class MyList
{
public MyList sort()
{
// Sort list
...
return sortedList;
}
}
then this is legal:
MyList list = MyClass.getList().sort();
In asp.net vb you can use a Module instead of a Class like this:
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Function extendedMethod(ByRef input As String) As String
Return input & "extended method"
End Function
End Module
Then in your code behind you import it the same as you would any class:
Imports Extensions
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim st As String = "a string "
Response.Write(st.ToUpper.extendedMethod)
End Sub
End Class
In this case you can use the "extendedMethod" method from the module on any string value in the same way you would use .toUpper() or .toLower()
Steve is right (no pun intended): Extension methods are what you're asking for. In C# you'd do something like this:
namespace ExtensionsNamespace; // Name this whatever you want.
public static class ListExtensions // must be public static!
{
// must be public static and the first parameter needs a "this"
public static IList<T> ToOrderedList<T>(this IList<T> originalList, IComparer<T> comparer)
{
// Code to take the original list and return an ordered version
}
}
And then in your code:
using ExtensionsNamespace;
...
IComparer<Book> comparer = GetBookComparer();
IList<BooK> books = GetBookList().ToOrderedList(comparer);
There are some additional things you can do using lambda expressions to avoid the need to write your own comparer class in certain cases, and so forth. However, before you go reinventing the wheel I'd suggest you look at LINQ to Objects, which already has a lot of these functionalities built in. For example:
using System.Linq;
...
IEnumerable<Book> booksInOrder1 = GetBookList().OrderBy(b => b.Title);
Does that answer your question?