8

C#のジェネリック型を考えると、null許容型とnull許容型に等しいT型を取得する方法がわかりません。QT?TTT

質問は実際のコードから生じました。ASP.NETアプリケーションのクエリ文字列を介して渡されるパラメーターへのアクセスを統一したい。また、同じタイプのデフォルト値を指定したいのですが、nullデフォルト値として渡すことができることを確認してください。

public static T FetchValue<T>(
   string name, 
   <T? for non-nullable, T otherwise> default_value = null)  // How to write this?
{
  var page = HttpContext.Current.Handler as Page;

  string str = page.Request.QueryString[name];

  if (str == null)
  {
    if (default_value == null)
    {
      throw new HttpRequestValidationException("A " + name + " must be specified.");
    }
    else
    {
      return default_value;
    }
  }

  return (T)Convert.ChangeType(str, typeof(T));
}

現在、私は2つのオーバーロードを強制されていFetchValueます。1つはデフォルト値なしで、もう1つはデフォルト値ありです。

public static T FetchValue<T>(string name);
public static T FetchValue<T>(string name, T default_value);

正常に動作しますが、このように両方の機能をマージできるのではないかと思います。

C ++では、null許容型とnull許容型の両方PromoteNullable<T>::typeの2つの特殊化のように、型特性を使用します。PromoteNullableしかし、C#はどうですか?

4

6 に答える 6

3

提起された質問に直接答えることはありませんが、私はこれを書きます:

    public static T FetchValue<T>(string name)
    {
        T value;
        if (TryFetchValue(name, out value))
            return value;
        throw new HttpRequestValidationException("A " + name + " must be specified.");
    }

    public static T FetchValue<T>(string name, T default_value)
    {
        T value;
        if (TryFetchValue(name, out value))
            return value;
        return default_value;
    }

    private static bool TryFetchValue<T>(
         string name,
         out T value)
    {
        var page = HttpContext.Current.Handler as Page;

        string str = page.Request.QueryString[name];

        if (str == null)
        {
            value = default(T);
            return false;
        }

        value = (T)Convert.ChangeType(str, typeof(T));
        return true;
    }

したがって、コードの大部分は1回だけ存在します。実際に、呼び出し元のコードにnullデフォルト値として選択させることができます(選択した場合)。


必要なパラメータ宣言を作成できたとしても、この行は依然として問題になります。

return default_value;

default_valueそれがではT?なくであることが判明した場合T、上記のコードは機能しません。キャストしても:

return (T)default_value;

まだ問題があります-からにキャストするT?Tは、コンパイラは実際にValuenullableのプロパティを取得するための呼び出しを挿入する必要があります。ただし、タイプが。の場合、その呼び出しは有効ではありませdefault_valueT

C#Genericsでは、コンパイラーはメソッド用に1つのILを作成する必要があります。にアクセスする可能性のあるオプションのコードを挿入する方法はありませんValue

于 2012-09-28T08:22:11.167 に答える
1

戻り型はTでありT、値型であるため、nullにすることはできません。したがって、nullを戻したいので、常にnull許容型を渡す必要がありますよね?

これを試してみてください。null許容値型(i)と通常の参照型(o)を渡すことができます。

static void Main(string[] args)
{
    int? i = 5;
    object x = new object();

    object o = FetchValue("x", i);
    o = FetchValue("x", x);
}

private static T? FetchValue<T>(string name, T? p) where T : struct
{
    T? result = (T?)FetchValue(name, (object)p);
    return result;
}

private static T FetchValue<T>(string name,
    T default_value = default (T)) // default(T) where T is a reference type will always be null!
    where T : class
{
    // do whatever you want
    var page = HttpContext.Current.Handler as Page;

    string str = page.Request.QueryString[name];

    if (str == null)
    {
        if (default_value == null)
        {
            throw new HttpRequestValidationException("A " + name + " must be specified.");
        }
        else
        {
            return default_value;
        }
    }

    return (T)Convert.ChangeType(str, typeof(T));
}

objectとにかくTの型になってしまうので、これがすべて構文fooであることを覚えておいてください。ただし、これは必須です。これは、object'sのみがnullになることができるためです。

于 2012-09-28T08:47:43.190 に答える
1

私の例があります:

//Page extension
static class PageExtensions
{
    private static T FetchValue<T>(this Page page, string name, object defaultValue)
    {
        string str = page.Request.QueryString[name];
        if (string.IsNullOrEmpty(str))
        {
            if (defaultValue != null)
                return (T)defaultValue;

            throw new HttpRequestValidationException("A " + name + " must be specified.");
        }

        //not the best way
        return (T)Convert.ChangeType(str, typeof(T));
    }

    public static T FetchValueFromCurrentPage<T>(string name, T defaultValue)
    { 
      var page = HttpContext.Current.Handler as Page;
      if(page == null)
        throw new InvalidOperationException("Current handler is not Page");
      return page.FetchValue<T>(name, defaultValue);
    }

    public static T FetchValueFromCurrentPage<T>(string name) where T : class
    {   
        return FetchValueFromCurrentPage(name, (T)null);
    }
}
于 2012-09-28T12:14:07.480 に答える
0

次のことを試してください。

private static T FetchValue<T>(string name, Nullable<T> default_value = null) where T : struct
{
    var page = HttpContext.Current.Handler as Page;

    string str = page.Request.QueryString[name];

    if (str == null)
    {
        if (default_value == null)
        {
            throw new Exception("A " + name + " must be specified.");
        }
        else
        {
            return (T)Convert.ChangeType(default_value, typeof(T));
        }
    }

    return default(T);
}

null許容型は値型である必要があるため、制約をに設定する必要がありますstructTタイプをとして宣言しNullable、値がある場合はタイプを変換します。それ以外の場合はdefault、タイプのを返しTます。この場合はnullです。このメソッドを呼び出すときは、次のようにタイプを明示的に設定する必要もあります。

int? val = FetchValue<int>("name");

文字列を返す

astringはnull許容の参照型であるため、この関数では使用できないと正しく言います。その場合、私は新しいものを作成し、struct文字列の場合は代わりにこれを使用します。

struct NullableString
{
    public string Value;
}

このような関数を呼び出します。

var val = FetchValue<NullableString>("blah", new NullableString() { Value = "default" });
于 2012-09-28T08:16:10.173 に答える
0

クラス制約を指定して、呼び出し元が参照型(null許容)を確実に渡すようにすることができます。

public static T FetchValue<T>(
   string name, 
   T default_value = null) where T : class //!
{
  var page = HttpContext.Current.Handler as Page;

  string str = page.Request.QueryString[name];

  if (str == null)
  {
    if (default_value == null)
    {
      throw new HttpRequestValidationException("A " + name + " must be specified.");
    }
    else
    {
      return default_value;
    }
  }

  return (T)Convert.ChangeType(str, typeof(T));
}

この場合、TをTにキャストする責任を委任しますか?発信者にとって必要な場合、それはとにかくいいです:彼はもっとよく知っているかもしれません!

于 2012-09-28T08:27:50.727 に答える
0

あなたはこの簡単な方法であなたが望むことをすることができます:

public static T FetchValue<T>(string name, T defaultValue = null) where T : class { }
public static T? FetchValue<T>(string name, T? defaultValue = null) where T : struct { }
于 2012-09-28T08:49:03.860 に答える