I've attempted to create an abstracted control to manage some of the state in our application. However, I have run a foul of some CLS issues and was hoping that someone could provide some insight.
I have an enumeration as such:
<Flags()> _
Public Enum FormState
Read = 1
Edit = 2
Insert = 4
End Enum
And a class as such:
Public MustInherit Class Fields
Inherits System.Web.UI.UserControl
Public Property State() As Enumerators.FormState
Get
Return _State
End Get
Set(ByVal value As Enumerators.FormState)
_State = value
ToggleState(value)
End Set
End Property
Protected MustOverride Sub ToggleState(ByVal state As FormState)
End Class
When I attempt to compile this code I am left with a warning that the State property is not CLS compliant and neither is the state argument. How come? And how can I correct this problem to remove the warnings?
I've attempted to add the <CLSCompliant(True)> attribute to both items with no luck
I tried to disseminate the MSDN article Non-CLS-compliant 'MustOverride' member is not allowed in a CLS-compliant into the code with no results
I've tried changing the accessors to Friend instead of Public
I've tried specifying a type for the Enum (Integer and UInteger)
Looking at your code, the enum seems to be part of a class called enumerators. The class is not listed in your code, but I'm assuming that you have full control over it.
The class needs to be tagged with the CLS compliant attribute as well.
To remove the warnings add the following attributes so that the class, method and property look like this:
<CLSCompliant(False)> _
Public MustInherit Class Fields
Inherits System.Web.UI.UserControl
<CLSCompliant(False)> _
Public Property State() As Enumerators.FormState
Get
Return _State
End Get
Set(ByVal value As Enumerators.FormState)
_State = value
ToggleState(value)
End Set
End Property
<CLSCompliant(False)> _
Protected MustOverride Sub ToggleState(ByVal state As FormState)
End Class
This signifies to the compiler that you want the warnings removed and that you're aware your code is not CLSCompliant.
It could be that you do not have an item with value 0.
Related
I have two objects, one is a base class and the other is a derived class which inherits the base class. One of the properties on the derived class overloads a property on the base class. Now, I want to perform some calculations on both of these objects one by one by passing them as a parameter into a function. The problem is, if I define the parameter of this function as a base class, then when passing the derived class, the value of the overloaded property gets lost!
The reason I'm using a derived class is to temporarily add more properties/modify the existing properties of the base class to perform additional calculations, in order to reuse the base class.
I've tried 4 different functions, but none of them are any good. They either don't work correctly, or there is duplicate code, which I need to avoid because there will be a lot more code later. Below is the pseudo code.
Defining the classes:
Class BaseClass
Public Property Name As String
Public Property Value As Integer
End Class
Class DerivedClass
Inherits BaseClass
Overloads Property Value As Double
End Class
Initializing:
Dim MyBaseObject As New BaseClass()
MyBaseObject.Name = NameOf(MyBaseObject)
MyBaseObject.Value = 5
Dim MyDerivedObject As New DerivedClass
MyDerivedObject.Name = NameOf(MyDerivedObject)
MyDerivedObject.Value = 5.3
Calling the functions:
ProcessClass1(MyBaseObject)
ProcessClass1(MyDerivedObject)
ProcessClass2(MyBaseObject)
ProcessClass2(MyDerivedObject)
ProcessClass3(MyBaseObject)
ProcessClass3(MyDerivedObject)
ProcessClass4(MyBaseObject)
ProcessClass4(MyDerivedObject)
The functions:
Sub ProcessClass1(inClass As Object) 'functions correctly, but no intellisense
Console.WriteLine(inClass.Name & " " & inClass.Value)
End Sub
Sub ProcessClass2(inClass As BaseClass) 'does not function correctly, but has intellisense
Console.WriteLine(inClass.Name & " " & inClass.Value) 'Value displays 0 when passing MyDerivedObject, it should be 5.3!
End Sub
Sub ProcessClass3(inClass As Object) 'functions correctly, has intellisense, but need to write code for all possible derived types in advance
If inClass.GetType = GetType(BaseClass) Then
Dim inBaseClass As BaseClass = inClass
Console.WriteLine(inBaseClass.Name & " " & inBaseClass.Value)
End If
If inClass.GetType = GetType(DerivedClass) Then
Dim inDerivedClass As DerivedClass = inClass
Console.WriteLine(inDerivedClass.Name & " " & inDerivedClass.Value)
End If
End Sub
Sub ProcessClass4(inClass As BaseClass) 'method overloading: functions correctly, has intellisense, but need to write a duplicate method for every derived type
Console.WriteLine(inClass.Name & " " & inClass.Value)
End Sub
Sub ProcessClass4(inClass As DerivedClass) 'method overloading: functions correctly, has intellisense, but need to write a duplicate method for every derived type
Console.WriteLine(inClass.Name & " " & inClass.Value)
End Sub
Extra: Generics
I don't see any advantage with generics, the below snipped runs into the same problem as ProcessClass2:
Dim MyProcessGenericObject As New ProcessGenericClass(Of BaseClass)
MyProcessGenericObject.processNewItem(MyBaseObject)
MyProcessGenericObject.processNewItem(MyDerivedObject)
Public Class ProcessGenericClass(Of T As BaseClass)
Public Sub processNewItem(ByVal newItem As T)
Console.WriteLine(newItem.Name & " " & newItem.Value) 'Value displays 0 when passing MyDerivedObject!
End Sub
End Class
Of these 4 functions, ProcessClass1 is the most elegant with the least amount of code, but there is no intellisense on inClass which makes it impossible to maintain.
What I need is no duplication of code, intellisense, a method which can take derived classes inherited from the same base class, and without losing the data contained in any overloaded properties. What would be the best way to achieve this? Thanks.
What you have put forward will not work with the instance you pass around being the base class. That instance's value property will always be an integer unless you are able to cast the instance to the appropriate derived class (and that (double)int cast is where you have lost precision).
But a combination of some of these generics may help. Note, the base class will not hold an integer, rather an Object.
Public Class BaseClass
Public Property Name As String
Public Property Value As Object
End Class
Public Class BaseClass(Of T)
Inherits BaseClass
Public Overloads Property Value As T
Get
Return CType(MyBase.Value, T)
End Get
Set(value As T)
MyBase.Value = value
End Set
End Property
End Class
Class DerivedClassDouble
Inherits BaseClass(Of Double)
End Class
Class DerivedClassInteger
Inherits BaseClass(Of Integer)
End Class
The process method
Sub ProcessClass(inClass As BaseClass)
Console.WriteLine($"{inClass.Name} {inClass.Value}")
End Sub
Some options for instantiation
Dim [myBase] As New BaseClass()
[myBase].Name = NameOf([myBase])
[myBase].Value = 5
Dim myBaseInteger As New BaseClass(Of Integer)
myBaseInteger.Name = NameOf(myBaseInteger)
myBaseInteger.Value = 5
Dim myDerivedInteger As New DerivedClassInteger
myDerivedInteger.Name = NameOf(myDerivedInteger)
myDerivedInteger.Value = 5
Dim myBaseDouble As New BaseClass(Of Double)
myBaseDouble.Name = NameOf(myBaseDouble)
myBaseDouble.Value = 5.3
Dim myDerivedDouble As New DerivedClassDouble
myDerivedDouble.Name = NameOf(myDerivedDouble)
myDerivedDouble.Value = 5.3
ProcessClass([myBase])
ProcessClass(myBaseInteger)
ProcessClass(myDerivedInteger)
ProcessClass(myBaseDouble)
ProcessClass(myDerivedDouble)
Console.ReadLine()
myBase 5
myBaseInteger 5
myDerivedInteger 5
myBaseDouble 5.3
myDerivedDouble 5.3
I think the closest to your implementation would be to use [myBase] and myDerivedDouble instances. Then changing the generic base class to Public MustInherit Class BaseClass(Of T) would make the intent clearer.
Hopefully last edit, sorry for the long-winded answer.
You can just change your original classes to have an object in the base class, and use the property implementation I laid out, and that seems to get the job done without any generics. Again, it may or may not work in your exact implementation
Sub Main()
Dim MyBaseObject As New BaseClass()
MyBaseObject.Name = NameOf(MyBaseObject)
MyBaseObject.Value = 5
Dim MyDerivedObject As New DerivedClass
MyDerivedObject.Name = NameOf(MyDerivedObject)
MyDerivedObject.Value = 5.3
ProcessClass(MyBaseObject)
ProcessClass(MyDerivedObject)
Console.ReadLine()
End Sub
Sub ProcessClass(inClass As BaseClass)
Console.WriteLine($"{inClass.Name} {inClass.Value}")
End Sub
Public Class BaseClass
Public Property Name As String
Public Property Value As Object
End Class
Public Class DerivedClass
Inherits BaseClass
Overloads Property Value As Double
Get
Return CDbl(MyBase.Value)
End Get
Set(value As Double)
MyBase.Value = value
End Set
End Property
End Class
MyBaseObject 5
MyDerivedObject 5.3
Been working a lot with custom classes lately and I love the power you can have with them but I have come across something that I'm not able to solve and/or find anything helpful online.
I have a list of a class with properties I'm looking to only store information pulled from a database into.
Public Class CustomClass
Public _Values As String
Public _Variables As String
Public ReadOnly Property Values() As String
Get
Return _Values
End Get
End Property
Public ReadOnly Property Variables() As String
Get
Return _Variables
End Get
End Property
Sub New(ByVal values As String, ByVal variables As String)
_Values = values
_Variables = variables
End Sub
End Class
I will be iterating through some database entries, and I'm looking to store them into the appropriate property when I hit them (since I won't have them all available immediately, which is part of my problem). I want to just be able to add either the value or the variable at a time and not both of them, but since I have the sub procedure 'New' passing two arguments, it will always require passing them both. I've found the only way around this is by making them optional fields which I don't feel is the right way to solve this. Is what I'm looking to do possible with a class or would it be simpler by using a structure?
You can overload the constructor:
Friend Class Foo
' using auto-implement props:
Public Property Name As String ' creates a _Name backing field
Public Property Value as Integer
Public Sub New(newN as String, newV as Integer)
' access "hidden" backing fields if you want:
_Name = newN
_Value = newV
End Sub
Public Sub New() ' simple ctor
End Sub
Public Sub New(justName As String)
' via the prop
Name = justName
End Sub
End Class
You now have 3 ways to create the object: with full initialization, partial (name only) or as a blank object. You will often need a "simple constructor" - one with no params - for other purposes: serializers, Collection editors and the like will have no idea how to use the parameterized constructors and will require a simple one.
If rules in the App were that there was no reason for a MyFoo to ever exist unless both Name and Value being defined, implementing only the New(String, Integer) ctor enforces that rule. That is, it is first about the app rules, then about coding convenience.
Dim myFoo As New Foo ' empty one
myFoo.Name = "ziggy" ' we only know part of it
Since the default of string is nothing, you could pass nothing for the value you don't have. IE
Collection.Add(New CustomClass("My Value",Nothing))
Every type has a default, so this works with more than just strings.
If I have a class object A, and it has properties such as a0, a1, a2... If this class has 100 properties like this (up to a99). I would like to display each of these properties, but I do not want to have 100 lines of code of calling this as following
print A.a0
print A.a1
print A.a2
...
print A.a99
The code is too inefficient, so I am wondering if there is a way to loop through these properties. Thank you.
.NET provides the ability to examine an object at runtime through a process known as reflection. The purpose of the original post was to iterate through an object's properties in an automated fashion rather than by manually coding explicit statements that displayed each property, and reflection is a process to accomplish this very thing.
For this particular purpose, looping through an object's properties at run-time, you use the GetProperties() method that is available for each Type. In your case, the Type you want to "reflect" is A, so the type-specific version of GetProperties returns a list of the instance properties for that object.
When you ask .NET to return the properties of an object, you can also specify what's called a binding flag that tells .NET which properties to return - public properties, private properties, static properties - a myriad of combinations from about twenty different values in the BindingFlags enumeration. For the purposes of this illustration, BindingFlags.Public will suffice, assuming your A0-A999 properties are declared to be public. To expose even more properties, simply combine multiple BindingFlag values with a logical "or".
So, now armed with that information, all we need to do is create a class, declare its properties, and tell Reflection to enumerate the properties for us. Assuming your Class A exists with property names A0-A999 already defined, here's how you'd enumerate ones starting with "A":
// Assuming Class "A" exists, and we have an instance of "A" held in
// a variable ActualA...
using System.Reflection
// The GetProperties method returns an array of PropertyInfo objects...
PropertyInfo[] properties = typeof(ActualA).GetProperties(BindingFlags.Public);
// Now, just iterate through them.
foreach(PropertyInfo property in properties)
{
if (property.Name.StartsWith("A")){
// use .Name, .GetValue methods/props to get interesting info from each property.
Console.WriteLine("Property {0}={1}",property.Name,
property.GetValue(ActualA,null));
}
}
There you have it. That's C# version rather than VB, but I think the general concepts should translate fairly readily. I hope that helps!
This MSDN code sample illustrates how to iterate over a class's properties using reflection:
http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx#Y900
Create a VB.Net Console application, copy and paste this code into the Module1.vb file and run it.
Module Module1
Sub Main()
For Each prop In GetType(TestClass).GetProperties()
Console.WriteLine(prop.Name)
Next
Console.ReadKey(True)
End Sub
End Module
Public Class TestClass
Private _One As String = "1"
Public Property One() As String
Get
Return _One
End Get
Set(ByVal value As String)
_One = value
End Set
End Property
Private _Two As Integer = 2
Public Property Two() As Integer
Get
Return _Two
End Get
Set(ByVal value As Integer)
_Two = value
End Set
End Property
Private _Three As Double = 3.1415927
Public Property Three() As Double
Get
Return _Three
End Get
Set(ByVal value As Double)
_Three = value
End Set
End Property
Private _Four As Decimal = 4.4D
Public Property Four() As Decimal
Get
Return _Four
End Get
Set(ByVal value As Decimal)
_Four = value
End Set
End Property
End Class
I have a POCO object and I want to mark a property as a key (see TestClass below).
I'm getting the following error.
'Key' cannot be used as an attribute because it is not a class. C:\Users\zzz\Documents\Visual Studio 2010\Projects\zzz\zzz\BO\TestClass.vb
Public Class TestClass
<Key()>
Private _TestIdentifier As String
Public Property TestIdentifier() As String
Get
Return _TestIdentifier
End Get
Set(ByVal value As String)
_TestIdentifier = value
' Me.NotifyPropertyChanged("TestIdentifier")
End Set
End Property
End Class
I had a missing import and reference
Imports System.ComponentModel.DataAnnotations
And reference System.ComponentModel.DataAnnotations.dll
I'm struggling a bit to understand the power behind OO programming. Granted I am only slightly experienced in coding in general, I was hoping this would come a lot easier than it has. For this example I created some basic code in order to determine if this is a correct/good way of containing objects within objects. If not, would you please guide me in the correct direction.
I have 2 classes: a Boy and a Dog Class. The Boy Class contains a Dog object. The Dog object knows who its owner is.
Here is a Boy class:
Public Class Boy
Protected mName As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
Protected mAge As Integer
Public Property Age() As Integer
Get
Return mAge
End Get
Set(ByVal value As Integer)
mAge = value
End Set
End Property
Protected mReturnHome As New TimeSpan(3, 15, 0)
Public Property ReturnHome() As TimeSpan
Get
Return mReturnHome
End Get
Set(ByVal value As TimeSpan)
mReturnHome = value
End Set
End Property
Protected mPet As New Dog(Me)
Public Property Pet() As Dog
Get
Return mPet
End Get
Set(ByVal value As Dog)
mPet = value
End Set
End Property
End Class
And here is a Dog class:
Public Class Dog
Private _owner As Boy
Public Sub New(ByRef Owner As Boy)
_owner = Owner
End Sub
Protected mName As String
Public Property Name() As String
Get
Return mName
End Get
Set(ByVal value As String)
mName = value
End Set
End Property
Protected mBreed As String
Public Property Breed() As String
Get
Return mBreed
End Get
Set(ByVal value As String)
mBreed = value
End Set
End Property
Protected mCanPlay As Boolean
Public Sub PlayBall()
If Now.TimeOfDay >= _owner.ReturnHome Then
mCanPlay = True
Else
mCanPlay = False
End If
End Sub
End Class
I need to be able to gain access to the Boy Class from the Dog Class because the Dog needs to be able to recognize properties specific to its owner (Boy).
Thank you.
First off, make your variables Private, not Protected. There is no need whatsoever for derived classes to access them directly.
Secondly, although this is done a lot in .NET, consider not having so many setters. Most properties shouldn’t change in an object’s lifetime. The exception are DTOs – objects which represent database entities.
Also take care only to model those aspects of an object that you actually use. In real software, most attributes of a given entity are irrelevant (e.g. hair colour of the customers in a library management software) and only a few are really needed by the software. Only model those.
Thirdly, if your Dog class needs to access specific functionality from the Boy class, the easiest recourse is to make this specific functionality Public.
Finally, don’t pass the dog’s owner via ByRef to the constructor. This works, but makes absolutely no sense. Use ByVal everywhere except where it really is required (and I argue that it’s never required, there are better solutions).
You're on the right track, although there are a few things that Boy and Dog have in common, such as Name and Age, so now you would look at those common attributes and methods and create a base class Animal from which both Boy and Dog would derive.
WRT how you tie the two together - consider that a boy could have multiple dogs, but a dog can have only one owner, so probably Boy.Dog should be Boy.Dogs (a collection) but Dog.Owner (as Boy) is absolutely fine.