Since the Google Ads API uses [proto3](https://protobuf.dev/programming-guides/proto3/) as its default payload format, it's
important to understand a few Protocol Buffers conventions and types when
working with the .NET client library.

## Optional fields

Many fields in the Google Ads API are marked as [`optional`](https://protobuf.dev/programming-guides/proto3/#field-labels). This lets you
distinguish between cases where the field has an empty value versus when the
server does not return a value for the field. These fields behave like regular
properties, except they also provide additional methods to clear the field and
to check if the field is set.

For example, the `Name` field of the `Campaign` object is marked as `optional`,
so you can use the following methods to work with this field:

    // Get the name.
    string name = campaign.Name;

    // Set the name.
    campaign.Name = name;

    // Check if the campaign object has the name field set.
    bool hasName = campaign.HasName();

    // Clear the name field. Use this method to exclude the Name field from
    // being sent to the server in a subsequent API call.
    campaign.ClearName();

    // Set the campaign name to an empty string value. This value will be
    // sent to the server if you use this object in a subsequent API call.
    campaign.Name = "";

    // This throws a runtime ArgumentNullException. Use ClearName() instead.
    campaign.Name = null;

## Repeated fields

A field array is represented in the Google Ads API as a read-only
[`RepeatedField`](https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/collections/repeated-field-t-).

For example, a campaign's `url_custom_parameters` field is a repeated field, so
it's represented as a read-only `RepeatedField<CustomParameter>` in the .NET
client library. `RepeatedField<T>` implements the [`IList<T>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ilist-1) interface.

There are two ways to populate a `RepeatedField` property:

### AddRange method

    Campaign campaign = new Campaign()
    {
        ResourceName = ResourceNames.Campaign(customerId, campaignId),
        Status = CampaignStatus.Paused,
    };

    // Add values to UrlCustomParameters using the AddRange method.
    campaign.UrlCustomParameters.AddRange(new CustomParameter[]
    {
        new CustomParameter { Key = "season", Value = "christmas" },
        new CustomParameter { Key = "promocode", Value = "NY123" }
    });

### Collection initializer syntax

    // Option 1: Initialize the field directly.
    Campaign campaign = new Campaign()
    {
        ResourceName = ResourceNames.Campaign(customerId, campaignId),
        Status = CampaignStatus.Paused,
        // Directly initialize the field.
        UrlCustomParameters =
        {
            new CustomParameter { Key = "season", Value = "christmas" },
            new CustomParameter { Key = "promocode", Value = "NY123" }
        }
    };

    // Option 2: Initialize using an intermediate variable.
    CustomParameter[] parameters = new CustomParameter[]
    {
        new CustomParameter { Key = "season", Value = "christmas" },
        new CustomParameter { Key = "promocode", Value = "NY123" }
    };

    Campaign campaign1 = new Campaign()
    {
        ResourceName = ResourceNames.Campaign(customerId, campaignId),
        Status = CampaignStatus.Paused,
        // Initialize from an existing array.
        UrlCustomParameters = { parameters }
    };

## Oneof fields

Some fields in the Google Ads API are marked as [`oneof`](https://protobuf.dev/programming-guides/proto3/#oneof) fields, meaning that
the field can hold different types but only one value at a given time. `oneof`
fields are similar to a union type in the C programming language.

The .NET library implements `oneof` fields by providing one property for each
type of value that can be held in a `oneof` field, with all the properties
updating a shared underlying storage field.

For example, the campaign's `campaign_bidding_strategy` is marked as a `oneof`
field. This class is implemented as follows (code simplified for brevity):

    public sealed partial class Campaign : pb::IMessage<Campaign>
    {
        object campaignBiddingStrategy_ = null;
        CampaignBiddingStrategyOneofCase campaignBiddingStrategyCase_;

        public ManualCpc ManualCpc
        {
            get
            {
                return campaignBiddingStrategyCase_ ==
                    CampaignBiddingStrategyOneofCase.ManualCpc
                    ? (ManualCpc)campaignBiddingStrategy_ : null;
            }
            set
            {
                campaignBiddingStrategy_ = value;
                campaignBiddingStrategyCase_ =
                    CampaignBiddingStrategyOneofCase.ManualCpc;
            }
        }

        public ManualCpm ManualCpm
        {
            get
            {
                return campaignBiddingStrategyCase_ ==
                    CampaignBiddingStrategyOneofCase.ManualCpm
                    ? (ManualCpm)campaignBiddingStrategy_ : null;
            }
            set
            {
                campaignBiddingStrategy_ = value;
                campaignBiddingStrategyCase_ =
                    CampaignBiddingStrategyOneofCase.ManualCpm;
            }
        }

        public CampaignBiddingStrategyOneofCase CampaignBiddingStrategyCase
        {
            get { return campaignBiddingStrategyCase_; }
        }
    }

Since `oneof` properties share storage, one assignment can overwrite a previous
assignment, leading to subtle bugs. For example:

    Campaign campaign = new Campaign()
    {
        ManualCpc = new ManualCpc(),
        ManualCpm = new ManualCpm()
    };

In this case, `campaign.ManualCpc` is `null` because initializing the
`campaign.ManualCpm` property overwrites the previous initialization for
`campaign.ManualCpc`.

## Conversion to other formats

### Convert to JSON format

You can convert protobuf objects to JSON format and back using
`Google.Protobuf.JsonFormatter`. This is useful when building systems that
need to interface with other systems requiring text-based formats like JSON
or XML.

    using Google.Protobuf;

    GoogleAdsRow row = new GoogleAdsRow()
    {
        Campaign = new Campaign()
        {
            Id = 123,
            Name = "Campaign 1",
            ResourceName = ResourceNames.Campaign(1234567890, 123)
        }
    };

    // Serialize to JSON and back.
    string json = JsonFormatter.Default.Format(row);
    row = GoogleAdsRow.Parser.ParseJson(json);

### Convert to bytes

You can serialize an object to bytes and back using `Google.Protobuf`.
Binary serialization is more memory- and storage-efficient than JSON format.

    using Google.Protobuf;

    GoogleAdsRow row = new GoogleAdsRow()
    {
        Campaign = new Campaign()
        {
            Id = 123,
            Name = "Campaign 1",
            ResourceName = ResourceNames.Campaign(1234567890, 123)
        }
    };

    // Serialize to bytes and back.
    byte[] bytes = row.ToByteArray();
    row = GoogleAdsRow.Parser.ParseFrom(bytes);