Events
Mar 17, 11 PM - Mar 21, 11 PM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
A partial member has one declaring declaration and often one implementing declaration. The declaring declaration doesn't include a body. The implementing declaration provides the body of the member. Partial members enable class designers to provide member hooks that can be implemented by tooling such as source generators. Partial types and members provide a way for human developers to write part of a type while tools write other parts of the type. If the developer doesn't supply an optional implementing declaration, the compiler can remove the declaring declaration at compile time. The following conditions apply to partial members:
The partial
keyword isn't allowed on constructors, finalizers, overloaded operators, or event declarations. Before C# 13, partial
wasn't allowed on properties or indexers.
A partial method isn't required to have an implementing declaration in the following cases:
private
).void
.out
parameters.virtual
, override
, sealed
, new
, or extern
.Any member that doesn't conform to all those restrictions (for example, public virtual partial void
method), must provide an implementation. Partial properties and indexers must have an implementation.
The following example shows a partial method that conforms to the preceding restrictions:
partial class MyPartialClass
{
// Declaring definition
partial void OnSomethingHappened(string s);
}
// This part can be in a separate file.
partial class MyPartialClass
{
// Comment out this method and the program
// will still compile.
partial void OnSomethingHappened(string s) =>
Console.WriteLine($"Something happened: {s}");
}
Partial members can also be useful in combination with source generators. For example a regex could be defined using the following pattern:
public partial class RegExSourceGenerator
{
[GeneratedRegex("cat|dog", RegexOptions.IgnoreCase, "en-US")]
private static partial Regex CatOrDogGeneratedRegex();
private static void EvaluateText(string text)
{
if (CatOrDogGeneratedRegex().IsMatch(text))
{
// Take action with matching text
}
}
}
The preceding example shows a partial method that must have an implementing declaration. As part of a build, the Regular expression source generator creates the implementing declaration.
The following example shows a declaring declaration and an implementing declaration for a class. Because the method's return type isn't void
(it's string
) and its access is public
, the method must have an implementing declaration:
// Declaring declaration
public partial class PartialExamples
{
/// <summary>
/// Gets or sets the number of elements that the List can contain.
/// </summary>
public partial int Capacity { get; set; }
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
/// <param name="index">The index</param>
/// <returns>The string stored at that index</returns>
public partial string this[int index] { get; set; }
public partial string? TryGetAt(int index);
}
public partial class PartialExamples
{
private List<string> _items = [
"one",
"two",
"three",
"four",
"five"
];
// Implementing declaration
/// <summary>
/// Gets or sets the number of elements that the List can contain.
/// </summary>
/// <remarks>
/// If the value is less than the current capacity, the list will shrink to the
/// new value. If the value is negative, the list isn't modified.
/// </remarks>
public partial int Capacity
{
get => _items.Count;
set
{
if ((value != _items.Count) && (value >= 0))
{
_items.Capacity = value;
}
}
}
public partial string this[int index]
{
get => _items[index];
set => _items[index] = value;
}
/// <summary>
/// Gets the element at the specified index.
/// </summary>
/// <param name="index">The index</param>
/// <returns>The string stored at that index, or null if out of bounds</returns>
public partial string? TryGetAt(int index)
{
if (index < _items.Count)
{
return _items[index];
}
return null;
}
}
The preceding example illustrates rules on how the two declarations are combined:
Capacity
property, the comments are taken from the implementing declaration. The implementing declaration comments are used when both declarations have ///
comments.///
comments.TryGetAt
, the comments are taken from the implementing declaration. The declaring declaration doesn't include any ///
comments.public
members.AllowMultiple=false
. The compiler recognizes any caller info attribute on the declaring declaration. All caller info attributes on the implementing declaration are ignored. The compiler issues a warning if you add caller info attributes on the implementing declaration..NET feedback
.NET is an open source project. Select a link to provide feedback:
Events
Mar 17, 11 PM - Mar 21, 11 PM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register now