views:

470

answers:

8

I am not sure if I have asked the question correctly. Please correct me if I am wrong.

Anyways, we would like to use a variable's value on a different phases of the page's life cycle.

So for example,

public partial class TestUserControl: UserControl{
    public TestUserControl(){
        Objects = new List<object>(){
            Property1,
            Property2,
            Property3
        };
    }

    public int Property1 { get; set; }
    public bool Property2 { get; set; }
    public string Property3 { get; set; }
    public List<object> Objects { get; set; }

    protected override OnLoad(EventArgs e){
        foreach(var item in Objects){
            Page.Controls.Add(new LiteralControl(item.ToString() + "<br/>"));
        }
    }
}

So if we say the values of Property1, Property2, Property3 are set as they were written on the tag, how could we use the properties' values just as when needed?

That on the constructor, instead of the values of the properties will be listed down on the List, only the Properties' names will be listed down so their current values will be used on OnLoad.

Thanks a lot.


Edit: I have adopted deerchao's and Jon's approach, but there seems to be another problem we will be facing... It's like:

public partial class TestUserControl: UserControl{
    public TestUserControl(){
        Objects = List<Func<object>>{
            () => Property1,
            () => Property2,
            () => Property3
        };
    }

    public int Property1 { get; set; }
    public bool Property2 { get; set; }
    public string Property3 { get; set; }
    public List<Func<object>> Objects { get; set; }

    protected override OnLoad(EventArgs e){
        foreach (var item in Objects) {
            //Here is the problem... can we get the variable name using this approach?
            //We have tried some other ways like reflection and expressions but to no avail. Help please =)
            string key = GetVariableName(item());

            string value = item() == null ? string.Empty : item().ToString();
            Page.Controls.Add(new LiteralControl(key + " : " + value + "<br/>"));
        }
    }
}
A: 

You need to override ToString() in your (Object) class to return the value. Or, provide a method or property to access the values directly.

FWIW, this has nothing to do with passing a variable by reference.

peacedog
That is not part of my problem though. I have just written the code this way to simplify my code here. Thanks anyways.
Jronny
Apologies if I misunderstood.
peacedog
No problem. Answer is appreciated =)
Jronny
+6  A: 

You can pass variables by reference (using ref) but not properties. Additionally, the "ref-ness" is only for the duration of the method: it aliases the argument and the parameter, but if you copy the parameter value into another variable, that other variable isn't an alias.

It's not really clear exactly what you want to do here, but you could use delegates instead:

    Objects = new List<Func<object>>(){
        () => Property1,
        () => Property2,
        () => Property3
    };

Then:

protected override OnLoad(EventArgs e){
    foreach(var itemRetriever in Objects){
        Page.Controls.Add(new Literal(itemRetriever().ToString() + "<br/>"));
    }
}

It's pretty nasty though - I'd try to find an alternative design if you can.

Jon Skeet
Jon: I think the OP's question is not related to calling by reference at all. The question, as I understand it, is mostly related to the way ASP.NET instantiates user controls that are declared in the markup.
Mehrdad Afshari
@Mehrdad: I'm not sure... I think he basically wants to be able to get at the properties later, in the given order. It's not very clear though.
Jon Skeet
Jon is partly correct here. I just want to basically get the values of the properties on the OnLoad event.
Jronny
@Jronny: Why don't you just access them directly?
Jon Skeet
I have some other settings and operators on the constructor and I don't want them to be separated. I actually use a parent class' OnLoad method, so other similar UserControls could just follow the framework
Jronny
+3  A: 

Seriously weird code, but how about:

public partial class TestUserControl: UserControl{
    public TestUserControl(){

    }

    public int Property1 { get; set; }
    public bool Property2 { get; set; }
    public string Property3 { get; set; }
    public List<object> Objects { get; set; }

    protected override OnLoad(EventArgs e){
        Objects = new List<object>(){
            Property1,
            Property2,
            Property3
        };

        foreach(var item in Objects){
            Page.Controls.Add(new Literal(item.ToString() + "<br/>"));
        }
    }
}
RichardOD
Actually, I have a more complicated code here, but this is just to break the problems down. There were quite a number of operations in the constructor, so i just want to have the list of objects set there already.
Jronny
A: 

Use the ref keyword when passing as reference

See This

ChadNC
well you can't do that to a Property.
deerchao
+1  A: 
public partial class TestUserControl: UserControl{
public TestUserControl(){
    Objects = new List<Func<object>>(){
        () => Property1,
        () => Property2,
        () => Property3
    };
}

public int Property1 { get; set; }
public bool Property2 { get; set; }
public string Property3 { get; set; }
public List<Func<object>> Objects { get; set; }

protected override OnLoad(EventArgs e){
    foreach(var item in Objects){
        Page.Controls.Add(new Literal(item().ToString() + "<br/>"));
    }
}

}

deerchao
I'll try this later.
Jronny
+1  A: 

Perhaps use PropertyDescriptor(s) in System.ComponentModel

System.ComponentModel.PropertyDescriptorCollection properties = System.ComponentModel.TypeDescriptor.GetProperties(this);
MaLio
A: 

You can't do it this way, but there are a few alternatives. For example:

public partial class TestUserControl: UserControl{

public int Property1 { get; set; }
public bool Property2 { get; set; }
public string Property3 { get; set; }
public IEnumerable<object> Objects
{
    get
    {
        yield return Property1;
        yield return Property2;
        yield return Property3;
    }
}

}

It's not a list, but you can still enumerate through it. You could also write an IList wrapper, although that would be lengthier.

Vilx-
Can we not set the `get` part of Objects while we are on a constructor?
Jronny
Properties are actually syntactic sugar for methods. What you have is two methods - get and set. So the best references you could have are delegates. Anyway, what is the problem with this solution?
Vilx-
We need to specify the properties that will be listed to Objects on the constructor.
Jronny
A: 

Ok, assuming I am understanding this correctly...

The values that are being displayed are "old" data. Data that gets changed during a later part of the Page Life-Cycle.

Assuming that is correct, change the OnLoad to OnRender (Or equivalent, can't remember off the top of my head)

And instead of adding Literal controls, you will just write the strings to an output stream (or a string? again, haven't done anything like this in a while...)

Does that help?

--Edit--

Ok, I finally understand what you are trying to do. I think heh.

You need to use reflection.

PropertyInfo[] props = typeof(TestUserControl).GetProperties(BindingFlags.Public);

That will get you all of the Public Properties of TestUserControl. Store that in your Objects array, then in OnLoad use:

object o =  props[0].GetValue(this, null);

to get the value.

Does that help you now? :)

TJMonk15
Well, there is no problem with literalcontrols or strings, it's just that no matter whether from PreInit to Unload, the data that is kept on the List. So instead of the data to be listed, what we need are the references of the properties to be kept. =)
Jronny
Uhm, as much as possible, we would not want to use Reflection here... And besides, only specific properties are needed, so getting all the public properties is not the way. Thanks. =)
Jronny
Without using Reflection, I have no idea heh.As for getting only certain properties, you can use Attributes to determine which properties to use.If my edit is what you want to do, I can't think of any way to do it without reflection because you are trying to right a base class that grabs Properties it doesn't know about at compile time.
TJMonk15