简体   繁体   中英

C# create a anonymous class

So my request may be strange.

Lets say I have a class CheckoutPage . I want a "property" Button that has the following:

  • Methods Displayed() and Click()
  • Property Text with a custom getter
  • Private constant locator that is an xpath to be used in the above methods

These should be accessed in the following way ( checkoutPage is an instance of CheckoutPage):

  • checkoutPage.Button.Click()

  • checkoutPage.Button.Displayed()

  • checkoutPage.Button.Text

One way of accomplishing this is to create a Button class and have:

public class Button{
    const string locator = "BUTTON_LOCATOR";
    private SeleniumDriver Driver;

    public Checkout(SeleniumDriver driver){
        this.Driver = driver;
    }

    public string Text{
        get {
            return Driver.FindElement(locator).Text;
        }
    }

    public bool Displayed(){
        return Driver.FindElement(locator).Displayed;
    }

    public void Click(){
        var button = Driver.FindElement(locator);
        new Actions(Driver).Click(button).Perform();
    }
}

public class CheckoutPage{
    private SeleniumDriver Driver;
    public Button Button;

    public CheckoutPage(SeleniumDriver driver){
        this.Driver = driver;
        this.Button = new Button(Driver);
    }
}

However this specific button class will only be used once and I don't want to have a class sitting around for each individual button on the page. So is there another way of doing this that preserves the CheckoutPage.Button.Something interface? Also would it be possible to not have to instantiate this

Maybe something similar to:

public class CheckoutPage{
    private SeleniumDriver Driver;

    public CheckoutPage(SeleniumDriver driver){
        this.Driver = driver;
    }

    public object Button {
        const string locator = "BUTTON_LOCATOR";

        public bool Displayed(){
            return Driver.FindElement(locator).Displayed;
        }

        public void Click(){
            var button = Driver.FindElement(locator);
            new Actions(Driver).Click(button).Perform();
        }

        public string Text{
            get {
                return Driver.FindElement(locator).Text;
            }
        }
    }
}

The deal with anonymous types is that they are always of local scope; a method can't return an anonymous type, for example, except by casting it to a named type (eg object ). That isn't very useful, because the caller won't have access to the type, so you won't get intellisense, early binding, or type safety.

The only workaround is to declare the type in the calling code and ask the method being called to use that as a template. For example, this would work:

public class Page
{
    public T Button<T>(T template) where T : class
    {
        return (T)Activator.CreateInstance
        (
            typeof(T), 
            new object[] 
            { 
                "Button text", 
                new Action(() => Console.WriteLine("This is a click handler")), 
                false 
            } 
        );
    }
}


public class Program
{
    static public void Main()
    {
        var template = new 
        { 
            Text = (string)null, 
            Click = (Action)null, 
            Displayed = false 
        } ;

        var page = new Page();
        var b = page.Button( template );

        Console.WriteLine(b.Text);
        Console.WriteLine(b.Displayed);
        b.Click();
    }
}

Output:

Button text
False
This is a click handler

Of course, if you pass it the wrong template, it will blow up.

I honestly doubt this sort of approach, or this line of thinking, will produce a cleaner or clearer solution than simply declaring a small class with three properties and returning it, as you are really supposed to.

I wouldn't recommend this method, at least as you have described it. The page object model is supposed to present an API to the consumer... a list of actions that can be accomplished on the page and not individual elements, eg buttons. The LoginPage page object should present the Login(string username, string password) method and not the username , password , and loginButton elements.

If you wanted to use this Button class that you are describing as an internal class that is used within a page object, that would better fit the page object model.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM