TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.77K subscribers
Post #2081 1.85K
День 1714. #ЗаметкиНаПолях
Как Получить Значение Типа по Умолчанию во Время Выполнения
При написании кода можно использовать значение default(T). Но что, если вы хотите сделать то же самое во время выполнения? Как получить значение по умолчанию для любого System.Type? (Допустим, вам это понадобилось)

В сети можно найти множество неправильных ответов. Например, этот:
object? GetDefaultValue(Type t) => 
t.IsValueType
? Activator.CreateInstance(t)
: null;

Это отлично работает для ссылочных типов и большинства типов значений. Но Activator.CreateInstance(T) — это не то же самое, что default(T), когда T является типом значения. Activator.CreateInstance(T) аналогичен new T(). То есть, он вызывает конструктор по умолчанию. default(T) не вызывает конструктор по умолчанию. Он инициализирует все поля значениями по умолчанию.

В C# 10 вы можете создать структуру с конструктором по умолчанию:
struct Sample
{
public int Value { get; }
public Sample() => Value = 1;
}

Посмотрим на разницу между default(Sample) и new Sample():
default(Sample).Value // 0

new Sample().Value // 1

Activator
.CreateInstance<Sample>()
.Value // 1

Так как же получить default(T) во время выполнения?

1. Использовать System.Linq.Expression, но это медленно (~20мс):
object? GetDefaultValue(Type t)
{
if (t.IsValueType)
{
var defExpr = Expression.Default(t);
return Expression
.Lambda(defExpr)
.Compile()
.DynamicInvoke();
}
return null;
}

2. Обобщённый класс со статическим свойством, которое возвращает значение обобщённого типа по умолчанию. Это быстрее (~2мс):
object? GetDefaultValue(Type t)
{
if (t.IsValueType)
{
var defType = typeof(DefaultProvider<>)
.MakeGenericType(t);
return defType
.InvokeMember("Value",
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.GetProperty,
binder: null,
target: null,
args: null,
culture: null);
}
return null;
}

private static class DefaultProvider<T>
{
public static T? Value => default;
}

3. Начиная с.NET Core, вы можете использовать System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject, чтобы получить неинициализированный экземпляр (~30нс):
object? GetDefaultValue(Type t)
{
if (t.IsValueType)
return RuntimeHelpers
.GetUninitializedObject(t);

return null;
}

Можно использовать любой из этих методов, чтобы получить значение по умолчанию:
((Sample)GetDefaultValue(typeof(Sample)))
.Value // 0

Источник: https://www.meziantou.net/get-the-default-value-of-a-type-at-runtime.htm
  • 👍 17
More from @netdeveloperdiary
  1. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
  2. Oct 8, 2026День 2808. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Начало В ИТ есть се…
  3. Oct 7, 2026День 2807. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Окончание Нач…
  4. Oct 6, 2026🦈 Открытое собеседование на Middle C# | 6 октября, 19:00 МСК Приглашаем на открытое собес…
  5. Oct 6, 2026День 2806. #ЗаметкиНаПолях Типы Коллекций в .NET, Которые Стоит Попробовать. Начало Больши…
  6. Oct 5, 2026День 2805. #ЧтоНовенького #NET11 Аргументы в Выражениях Коллекций в C#15 В C#15 реализован…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →