I have to following in vb.net and am having a rough time converting to c#. The fieldlist is a class that has several properties however only 2 are relevant for the below procedure. The code to call the procedure looks like myClass.Fields("Test") = 123456. The converters all drop the fieldname from the property. If I add it back then I get The name 'value' does not exist in the current context.
VB.net - works fine in VB
Public WriteOnly Property Fields(ByVal fieldName As String) As Object
Set(ByVal value As Object)
If mvarFieldData Is Nothing Then mvarFieldData = New FieldList
If mvarFieldData(fieldName) Is Nothing Then
mvarFieldData.Add(fieldName, value)
Else
mvarFieldData(fieldName).FieldValue = value
End If
End Set
End Property
c# - I'm doing something wrong here.
public object Fields(string fieldName)
{
set {
if (mvarFieldData == null)
{mvarFieldData = new FieldList();}
if (mvarFieldData[fieldName] == null)
{
mvarFieldData.Add(fieldName, value);
} else {
mvarFieldData[fieldName].FieldValue = value;
}
}
}
c# Converters(telerik) provide the below
public object Fields {
set {
if (mvarFieldData == null)
mvarFieldData = new FieldList();
if (mvarFieldData(fieldName) == null) {
mvarFieldData.Add(fieldName, value);
} else {
mvarFieldData(fieldName).FieldValue = value;
}
}
}
What is the scope of mVarFieldData, and what is it's exact type? It seems like it is a Collection of some sort.
The c# code above is not compilable as you are trying to mix a method syntax with a property syntax.
property:
public object Fields{ get; set{mvarFieldData = value;} }
Method:
public object Fields(string fieldname, object val){ mvarFieldData[fieldname] = val;}
By the looks of the decision making going on in the VB.Net property, I would think a public method may suit the situation better. I normally just use property's when a very minimum amount of validation is needed when setting a encapsulated type member.
Hope this helps.
You actually have a couple problems here.
Problem 1: Properties don't take arguments.
C# properties can't be passed an argument/parameter the way you're passing fieldname. There are a couple different ways you could solve this:
You can make an index property (used with myObject[fieldName] = blah rather than myObject.Fields[fieldName] = blah). Use the syntax public object this[string fieldName] to declare the property.
Since your property doesn't have a getter, you can just turn it into a single method with signature public void SetField(string fieldName, object value), called like so: myObject.SetField(fieldName, value).
You can expose mvarFieldData through a getter property: public Dictionary<?, ?> Fields { get { return mvarFieldData; } } which will let users access the dictionary (I assume that's what it is, based on usage) directly.
Problem 2: The key may not exist.
I'm not sure about dictionaries (or whatever similar structure mvarFieldData is) in VB.NET, but in C# there's a difference between a key whose value is null and a key that's not present in the structure.
var dict = new Dictionary<int, string>();
dict.Add(1, null);
if (dict[1] == null)
Console.WriteLine("This line will be displayed.");
if (dict[2] == null)
Console.WriteLine("The line above this one will throw an exception.");
In addition to your present code, you need a check for mvarFieldData.ContainsKey(fieldName) before you start checking the value associated with fieldName.
Related
I want to option to set a property with multiple types and am struggling to find a solution.
public static PropertyType Property
{
get { return Property;}
set {
if (value.GetType() == typeof(PropertyType))
{
Property = value;
}
//Or any other type
if (value.GetType() == typeof(string))
{
Property = FunctionThatReturnsPropertyType(value);
}
}
}
I hope that makes sense, I am only ever setting the Property as one type but I would like to be able to assign to it with other types and then transform them within the setter - is this possible?
What you want looks like design error.
In C# property's setter and getter have always the same type. So you have basically next choices:
Make your property type object (or dynamic if you want to get even worse design) and transform values within the setter as you stated in the question - i strongly recommend to avoid this approach.
Get away from property concept and create separate methods to get value of the field and assign from different types. This approach will allow you to assign value if you dont know the type at compile-time while getter-method will be typed still correctly. But generally it still looks like bad design.
Make all the transformations outside the property, This solution is preferred. You should know which type you will use in every separate case.
Try Property type as object.
public static Object PropertyName
{
get { return PropertyName; }
set { PropertyName = value; }
}
In my CustomView class, TaskText and ProjectText are comboboxes. See the following property written for getting value from TaskText. My TaskText combobox contains list of Tasks. When I select specific task at runtime, it should store id of that Task which I've done in setters. But I don't understand, how do I get that id?
Later, I'll convert that id to integer and passed to method.
See the below code, which I've tried-
public Harvest_Task taskClass
{
get
{
return new Harvest_Task { _id = Int32.Parse(TaskText.Text) }; // Here _id doesn't take the value.
}
set
{
if (value != null)
{
TaskText.Text = (value._id).ToString();
}
}
}
Usually you create a getter/setter to a specific property of a class and not the whole class itself...
Plus the way you're trying to do things, i recomment trying a Singleton class.
Scenario:
i have a web form from where i m taking input for Item class now i want to assign values to feature that have return type of list how can i do that.
item value = new item(),
value.feature = serialtextbox.text; //error
foreach ( var item in value) //error
{
item.SerialNo= serialtextbox.text;
}
Item and Item feature classes
Class Item
{
list<Itemfeature> features;
}
class ItemFeature
{
public int SerialNo
{
get { return serialno; }
set { serialno = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
Plz help me out
Note: No language is specified, but it looks like C#. I'm assuming C# in this answer.
It's not really clear what you're trying to do here, but I'll give it a shot. First of all, you're going to want to post the actual code you're using. This code won't even compile, it's loaded with syntax errors.
Let's take a look at your objects first:
class Item
{
List<ItemFeature> features;
}
class ItemFeature
{
public int SerialNo
{
get { return serialno; }
set { serialno = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
You have a custom class, ItemFeature, which consists of a serial number (integer) and a weight (integer). You then have another custom class, Item, which consists of a list of ItemFeatures.
Now it looks like you're trying to add a new ItemFeature to the Item and then loop through all of them and set them again?. Something like this, perhaps?:
Item value = new Item();
value.features.Add(new ItemFeature { SerialNo = int.Parse(serialtextbox.Text) } );
foreach (var item in value.features)
{
item.SerialNo = int.Parse(serialtextbox.Text);
}
(Note that this code is probably as free-hand as your code, so I haven't tested it or anything.)
What I've changed here is:
Setting the SerialNo property, rather than trying to set the ItemFeature directly to a value. You need to dig into the object's property to set a value on that property, not just set it to the entire object.
Converting the input (a string) into the property's type (an int).
Looping through the list, not the Item object itself. The Item object contains a list as a property, but the object itself isn't a list. You can loop through the property, not through the parent object.
A few things to ask/note:
What exactly are you trying to do? You have a list of objects, but you're only setting one and then looping through that one to set it again. Why?
You may want to consider more apt class/property names. Things like "Item" can be a bit unclear.
Your Item class has a public variable, features. This is generally frowned upon. It's better to use a property. That way if you ever have to add logic behind it you won't break compatibility outside of the object itself. The ItemFeature class has properties like this, which is good. They can be additionally shortened by using automatic properties if you'd like, just to keep things clean and simple.
Note that my code isn't doing any input checking on the serialtextbox.Text value. It should be. I presented it in a simpler form as an introductory approach to something that will work under ideal conditions. But something like the following would be better:
var serialValue = 0;
if (!int.TryParse(serialtextbox.Text, out serialValue))
{
// Here you would probably present an error to the user stating that the form field failed validation.
// Maybe even throw an exception? Depends on how you handle errors.
// Mainly, exit the logic flow.
return;
}
var value = new Item();
value.features.Add(new ItemFeature { SerialNo = serialValue } );
Edit: I just noticed that my call to .Add() will actually fail. You'll want to initialize the list before trying to use it. Consider changing the Item class to something like this:
class Item
{
public List<ItemFeature> features { get; set; }
public Item()
{
features = new List<ItemFeature>();
}
}
Two things changed here:
I converted the public member to a property, as previously mentioned.
I added a constructor which initializes the list so that it can be used. Otherwise, being a reference type, it would default to null. So any call to .Add() or any other method on the list would throw a NullReferenceException because there's no object on which to call the method(s).
Per the MSDN documentation, the following syntax is used:
// A read-write instance property:
public string Name
{
get { return name; }
set { name = value; }
}
However, the following code is generated by VS2010 automatically for a new library class:
public string Name
{
get
{
String s = (String)ViewState["Name"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Name"] = value;
}
}
When is it appropriate to use the ViewState syntax over the shorter example shown on MSDN?
ViewState is a feature of ASP.Net server controls that persists information across postbacks.
For simple properties that aren't in a server control, you should use an auto-implemented property:
public string Name { get; set; }
The first stores the value in a private property field inside the class, while the second (tries to) store the actual value in the ViewState.
So the 2nd is only possible when you are talking about ASP controls with viewstate enabled, which is a narrow subset of all possible cases.
A C# property is just a piece of syntactic sugar. This structure
public Foo MyValue { get ; private set ; }
is exactly as if you coded:
private Foo _myValue ;
public Foo
{
get
{
return _myValue ;
}
private set
{
this._myValue = value ;
}
}
In either case, the code that actually gets generates is pretty much this:
private Foo _myValue ;
public Foo MyValue_get()
{
return this._myValue ;
}
private Foo MyValue_set( Foo value )
{
this._MyValue = value ;
}
If you opt to instantiate your own getter/setter, then what happens in the body of the getter/setter is entirely up to you. There is no "right" or wrong: it's dependent on the needs of your program.
With respect to ViewState, ViewStateis a piece of ASP.Net. It has little do with properties one way or another. You example just exposes a ViewState item as a public read/write property.
The difference between the two is that one is just plain old C# property providing access to a (most likely) privately scoped variable in your class.
The other one is returning a value recovered from ASP.NET's ViewState.
These are two different things altogether.
Say I have a C# Nullable DateTime? property that needs to be consumed by VBA through COM.
public DateTime? TestDate {
get ; set;
}
Unfortunately, Nullables are not visible through COM, so I would like to have the property return a something that will be seen as a Variant from VBA.
Unfortunately, I'm not sure how this should be written.
I tried using an object and a dynamic instead of DateTime?: while I can get the property value, I can't set it (I get Run-Time error '424' Object required errors from VBA).
Note: I don't have issues with making my library COM Visible: everything works fine and I'm able to use .Net types from VBA without problem, except for this particular issue.
Thanks for any pointers.
EDIT: I found an interesting page describing the default marshalling for objects, but I can't seem to explain why I can't set my property if it's declared as object.
I'm missing something.
Here what I did to go around the issue.
Object properties
public object MyObject {
get ; set;
}
When using a .Net Object property from VBA, reading the property is no problem and it will be correctly seen as a Variant.
Unfortunately, trying to set the property from VBA will fail.
However, using plain methods will work fine:
private object _MyObject;
public object GetMyObject() {
return _MyObject;
}
public void SetMyObject(object value) {
if (value == DbNull.Value)
value = null;
_MyObject = value;
}
The check for DBNull is to get around the problem that VBA' Null is actually marshalled as DBNull to .Net.
DateTime?
Now, to make nullable DateTime? work, we can do something like:
private DateTime? _MyDate;
public object GetMyDate() {
return _MyDate
}
public void SetMyDate(object value) {
if (value == null || value == DbNull.Value)
_MyDate = null;
else
_MyDate = (DateTime?)value;
}
And in VBA, we can hide these get/set in properties (assuming we have an existing instance of our class in myclassinstance):
Public Property Get MyDate() As Variant
MyDate = myclassinstance.GetMyDate()
End Property
Public Property Set MyDate(value as Variant)
myclassinstance.SetMyDate value
End Property
A more generic way
This is a bit ugly since our C# class is exposing MyDate as GetMyDate/SetMyDate methods instead of properties.
To implement this in a more generic way so the mechanism is usable for all properties in our class, we can use a Dictionary as a backing store:
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class MyClass {
private Dictionary<string,object> backingStore = new Dictionary<string,object>();
public object GetPropertyValue(string propertyName) {
if (backingStore.ContainsKey(propertyName))
return backingStore[propertyName];
else
return null
}
public void SetPropertyValue(string propertyName, object value) {
if (value == DBNull.Value) value = null;
if (backingStore.ContainsKey(propertyName))
backingStore[propertyName] = value;
else
backingStore.Add(propertyName, value);
}
[ComVisible(false)]
public DateTime? MyDate {
get {
return GetPropertyValue(#"MyDate") ?? default(DateTime?);
}
set {
SetPropertyValue(#"MyDate", value);
}
}
}
The ComVisible(false) attribute ensures that the properties are not visible from VBA.
And in VBA, we declare the properties:
Public Property Get MyDate() As Variant
MyDate = myclassinstance.GetPropertyValue("MyDate")
End Property
Public Property Set MyDate(value as Variant)
myclassinstance.SetPropertyValue "MyDate", value
End Property
Create your own NullableDateTime class with the Nullable features such as HasValue and Value properties and GetValueOrDefault method.