2

I want to build a form entity, which should contain form form fields, so I want to have a class that looks something like this:

public abstract class form
{
    public string FormName;
    public IList<FormField> Fields;
}

I want my FormField class to have one method: getValue, but I want it to be generic, so getValue would not return an Object but the actual value of the object.

4
  • 2
    Rather than discussing what you want the signature of GetValue to look like, tell us how you want to write the consumer of the Fields list that calls GetValue. Can you explain how this thing is going to be used, because I am not understanding what you want here. Commented Feb 25, 2010 at 15:17
  • 1
    The .Net convention is to PascalCase classnames, that is, let each "word" in a class' name begin with a capital. In your case, replaces form with Form. You can see the convention as both IList and FormField are PascalCased. String, Int32 and other so called base types have all a lowercase equivalent though, eg. string and int, but that is C# specific and not exposed to the outside. Commented Feb 25, 2010 at 15:18
  • Don't know if its a duplicate, but would this be helpful to you: stackoverflow.com/questions/1848312/… Commented Feb 25, 2010 at 15:25
  • 1
    Is the list of fixed size, where you know ahead of time the types that are going to be in each position? That is, do you know that the first position will be a number and the second will be a string, and so on? If so, then you want a tuple, not a list. Commented Feb 25, 2010 at 15:41

5 Answers 5

3

Unfortunately there is no way to create a single generic list containing objects, that each have a different return type for a given method, like the one you want.

The best you can do is an interface, or base class, and a method that returns Object.

This means you will have to cast, but then, you would have to do that anyway.

How would this code work if you could have different return types:

FormField f = _Fields[0];
?? x = f.GetValue();
Sign up to request clarification or add additional context in comments.

5 Comments

hmmm, i think your right there, i thought something along the lines of the var, but from what i understand thats just a syntactic sugar in c#
Correct, "var" is not dynamic, you might be able to do this with the dynamic keyword (at least from the "var" point of view), but you would still not be able to have differing return types. I would take your code two steps back and try to see if there is a different way to accomplish your goals.
Is there any other good way to implement this, so you're saying i must give up on explicit type checking?
Would you please check out my sample code below & see if that works? I think there might be a way to do this with help of generic + linq...
In order to have type checking, you need to be able to determine what the types of all the expressions are in advance. Under the scheme you're proposing, there is no way to do that, so what would actually be checked?
3

This will work:

public abstract class Form<T>{
  public string FormName;
  public IList<IFormField> Fields;
}

public class FormField<T> : IFormField{
    public T getValue() { return default(T); }

    object IFormField.getValue() {  
        return this.getValue();
    }
}

public interface IFormField { 
      object getValue();
}

4 Comments

This will work, but again, this will not ensure that i'll have the GetValue method on each item inside the list, this is more of a workaround then a solution.
@MindFold: I've added a getValue method to the interface which should address that problem.
mmm, how that will work? will it return me an Object or the T?
@Mindfold: I've corrected some syntax errors, but will return the instance of T, cast as an object, which is really the best you can possibly hope for, given that Fields contains multiple types of T.
1

public abstract class Form<T>{
  public string FormName;
  public IList<FormField<T>> Fields;
}

public class FormField<T>{
  public T getValue { ... code here ...  }
}

2 Comments

That means my form will only contain,for example string fields, but thats not what i want, i want to be able for it to contain many diffrent types of fields.
@MindFold: I've modified this solution using an interface to accomplish what you're looking for.
1
public abstract class Form {
    public IList<FormField> Fields;
    public string FormName;
}

public class FormField {
    private Object field;

    public T getValue<T>() {
        return (T) field;
    }
}

Comments

1

Please see the complete code below. My solution works like:

var myForm = new Form();
var int_value = myForm.Fields
           .OfType<IntegerFormField>()
           .First(c => c.Name == "c1").GetValue();
var decimal_value = myForm.Fields
           .OfType<DecimalFormField>()
           .First(c => c.Name == "c2").GetValue();

The field interfaces:

    public interface IFormField
    {
        object GetValue();
        string Name { get; }
    }

    public interface IFormField<T> : IFormField
    {
        T GetValue();

    }

The abstract base class for all form fields:

abstract class FormFieldBase<T> : IFormField<T>
        {
            private readonly T _value;

            public FormFieldBase(T value, string name)
            {
                _value = value;
                Name = name;
            }

            #region IFormField<T> Members

            public virtual T GetValue()
            {
                return _value;
            }

            #endregion

            #region IFormField Members

            object IFormField.GetValue()
            {
                return _value;
            }

            public string Name { get; private set; }

            #endregion
        }

Two sample form field implementation:

class IntegerFormField : FormFieldBase<int>
{
     public IntegerFormField(int value, string name) : base(value, name) { }
}

class DecimalFormField : FormFieldBase<decimal>
{
     public DecimalFormField(Decimal value, string name) : base(value, name) { }
}

The Form Class:

class Form
    {
        public IList<IFormField> Fields
        {
            get
            {
                return new List<IFormField>(){
                        new IntegerFormField(10, "c1"), 
new DecimalFormField(200, "c2")
                 };
            }
        }
    }

HTH

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.