Есть ли способ указать параметр общего типа как имеющий конструктор, который принимает строку? [Дубликат]

Если вы не инициализировали ссылочный тип и хотите установить или прочитать одно из его свойств, он будет генерировать исключение NullReferenceException.

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

17
задан svick 16 March 2012 в 19:40
поделиться

5 ответов

Это невозможно. Я хотел бы увидеть «статические интерфейсы» , чтобы справиться с этим, но не ожидайте их в ближайшее время ...

Альтернативы:

  • Укажите делегата для работы в качестве фабрики для T
  • Укажите другой интерфейс для работы в качестве фабрики для T
  • Укажите интерфейс для самого T для инициализации (и добавьте ограничение, чтобы что T реализует интерфейс)

Первые два действительно эквивалентны. В основном вы измените свой прокси-класс на что-то вроде этого:

public class GenericProxy<T>
    where T: ClientBase, new()
{
    string _configName;
    T _proxy;
    Func<string, T> _factory;

    public GenericProxy(Func<string, T> factory, string configName)
    {
        _configName = configName;
        _factory = factory;
        RefreshProxy();
    }

    void RefreshProxy() // As an example; suppose we need to do this later too
    {
        _proxy = _factory(_configName);
    }
}

(я предполагаю, что вы захотите создать больше экземпляров позже - иначе вы могли бы также передать экземпляр T в конструктор.)

24
ответ дан Jon Skeet 27 August 2018 в 07:27
поделиться

К сожалению, что вы пытаетесь сделать, невозможно.

Статья MSDN по ограничениям типов

4
ответ дан Joseph 27 August 2018 в 07:27
поделиться

Как отмечает Джон, для этого нет встроенной поддержки, но в качестве альтернативы вы можете создать типизированный делегат для конструктора (быстрее, чем отражение), используя Expression. Код для этого можно найти в MiscUtil MiscUtil.Linq.Extensions.TypeExt).

1
ответ дан Marc Gravell 27 August 2018 в 07:27
поделиться

Вот полный рабочий пример, основанный на ответе @JonSkeet:

using System;
using System.Collections.Generic;

namespace GenericProxy
{
    class Program
    {
        static void Main()
        {
            GenericProxy<ClientBase> proxy = new GenericProxy<ClientBase>(ClientBase.Factory, "cream");

            Console.WriteLine(proxy.Proxy.ConfigName); // test to see it working
        }
    }

    public class ClientBase
    {
        static public ClientBase Factory(string configName)
        {
            return new ClientBase(configName);
        }

        // default constructor as required by new() constraint
        public ClientBase() { }

        // constructor that takes arguments
        public ClientBase(string configName) { _configName = configName; }

        // simple method to demonstrate working example
        public string ConfigName
        {
            get { return "ice " + _configName; }
        }

        private string _configName;
    }

    public class GenericProxy<T>
        where T : ClientBase, new()
    {
        public GenericProxy(Func<string, T> factory, string configName)
        {
            Proxy = factory(configName);
        }

        public T Proxy { get; private set; }
    }
}

Ожидайте увидеть следующий вывод: ice cream

0
ответ дан Tom Wilson 27 August 2018 в 07:27
поделиться

Это не отвечает на ваш реальный вопрос, ограничивая метод, но для полноты здесь вы можете делать то, что вы спрашиваете во время выполнения, используя отражение:

private T  Get<T>(string id)
    {
    var  constructor = typeof(T).GetConstructor(new Type[] { typeof(X), typeof(Y) });
    if (constructor == null)  throw new InvalidOperationException("The type submitted, " + typeof(T).Name + ", does not support the expected constructor (X, Y).");

    var  data = GetData(id);
    return (T)constructor.Invoke(new object[] { data.x, data.y });
    }
2
ответ дан user 27 August 2018 в 07:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: