0

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/>"));
        }
    }
}
Jronny
  • 2,164
  • 4
  • 30
  • 41
  • I read this three times and I still don't understand what you're trying to do nor what it has to do with passing by reference. – jason Dec 08 '09 at 15:33
  • 1
    Jason, I think the reference thing is an inadvertent redherring. Maybe I read this wrong, but it sounds like Jronny is unhappy with the results of item.ToString(). But please keep in mind I'm a lot. – peacedog Dec 08 '09 at 15:37
  • I've changed the title of the question to what I think he's asking. If it's wrong, please change it back. – dtb Dec 08 '09 at 15:37
  • 1
    @peacedog: I don't think so. I think the issue is that he is storing the values of `Property1`, `Property2` and `Property3` at the time that `TestUserControl` is constructed, but the values of those properties could have changed when `OnLoad` is executed. Therefore he is seeing "old" values on the control instead of their current values. The solution is to just move the creation of `Objects` to the `OnLoad` method. – jason Dec 08 '09 at 15:48
  • Jason is right. But if there is just a way we could get the "new" values listing down the properties, and getting their newest values during the OnLoad event... @peacedog: the toString() here is just to show that the values of the properties are shown. I do not have problem with that though. – Jronny Dec 08 '09 at 15:56

8 Answers8

6

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 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 Dec 08 '09 at 15:36
  • @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 Dec 08 '09 at 15:42
  • Jon is partly correct here. I just want to basically get the values of the properties on the OnLoad event. – Jronny Dec 08 '09 at 15:50
  • 1
    @Jronny: Why don't you just access them directly? – Jon Skeet Dec 08 '09 at 15:58
  • 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 Dec 08 '09 at 16:03
3

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
  • 28,883
  • 9
  • 61
  • 81
  • 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 Dec 08 '09 at 15:58
1
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
  • 10,454
  • 9
  • 55
  • 60
1

Perhaps use PropertyDescriptor(s) in System.ComponentModel

System.ComponentModel.PropertyDescriptorCollection properties = System.ComponentModel.TypeDescriptor.GetProperties(this);
MaLio
  • 2,498
  • 16
  • 23
0

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
  • 1,415
  • 20
  • 32
0

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-
  • 104,512
  • 87
  • 279
  • 422
  • Can we not set the `get` part of Objects while we are on a constructor? – Jronny Dec 08 '09 at 16:30
  • 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- Dec 08 '09 at 16:36
  • We need to specify the properties that will be listed to Objects on the constructor. – Jronny Dec 08 '09 at 16:57
0

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? :)

FallenAvatar
  • 4,079
  • 1
  • 21
  • 24
  • 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 Dec 08 '09 at 16:24
  • 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 Dec 08 '09 at 16:53
  • 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. – FallenAvatar Dec 09 '09 at 14:39
-1

Use the ref keyword when passing as reference

See This

ChadNC
  • 2,528
  • 4
  • 25
  • 39