2011-07-16 14 views
2

オブジェクトをIsolated Storageから取得するクラスがあります。問題のオブジェクトが見つからない場合は、デフォルト(T)を返します。これは参照型であるため、nullになります。返される値がnullの場合は、単純なチェックを行い、呼び出し側で新しいインスタンスを割り当てますが、ストレージロジックでこれを行うことをお勧めします。ジェネリックでnullインスタンスではなく新しいインスタンスを返します

私の質問は、オブジェクトにデフォルトの空白のコンストラクタがある新しいTを返す方法があるかどうかです。

+0

[Activator.CreateInstanceを介してnull可能オブジェクトを作成すると、nullを返す](http://stackoverflow.com/questions/8691601/creating-a-nullable-object-via-activ-createinstance-returns- null) – nawfal

答えて

13

オプションは、「新しい」contraintを使用することになります。 http://msdn.microsoft.com/en-us/library/sd2w2ew5(v=vs.80).aspx

ので、同じように:

public T GetNewItem() 
    where T: new() 
{ 
    return new T(); 
} 

しかし、この制約を持つことは、あなたが持っていないタイプを使用できないことを意味しますデフォルトコンストラクタ。だから、System.Activator.CreateInstanceを使用することを考えるが、それは例外をスローすることがあることを覚えて:

T createInstance<T>() 
{ 
    try 
    { 
     return System.Activator.CreateInstance<T>(); 
    } 
    catch (MissingMethodException exc) 
    { 
     return default(T); 
    } 
} 

だから、与えられた型が初期化で、これは早期にサポートしているかどうかを知るのは良い考えかもしれ、Aそうするための方法は次のとおりです。

T createInstance<T>() 
{ 
    System.Reflection.ConstructorInfo constructor = (typeof(T)).GetConstructor(System.Type.EmptyTypes); 
    if (ReferenceEquals(constructor, null)) 
    { 
     //there is no default constructor 
     return default(T); 
    } 
    else 
    { 
     //there is a default constructor 
     //you can invoke it like so: 
     return (T)constructor.Invoke(new object[0]); 
     //return constructor.Invoke(new object[0]) as T; //If T is class 
    } 
} 

あなたがそれでありながら、なぜインスタンスを作成し、デリゲートを取得していませんか?

Func<T> getConstructor<T>() 
{ 
    System.Reflection.ConstructorInfo constructor = (typeof(T)).GetConstructor(System.Type.EmptyTypes); 
    if (ReferenceEquals(constructor, null)) 
    { 
     return() => { return default(T); }; 
    } 
    else 
    { 
     return() => { return (T)constructor.Invoke(new object[0]); }; 
    } 
} 

それを使用する方法の例(LinqPadでコンパイル):

void Main() 
{ 
    Console.WriteLine(getConstructor<object>()()); 
    Console.WriteLine(getConstructor<int>()()); 
    Console.WriteLine(getConstructor<string>()()); 
    Console.WriteLine(getConstructor<decimal>()()); 
    Console.WriteLine(getConstructor<DateTime>()()); 
    Console.WriteLine(getConstructor<int?>()()); 
} 

出力である:

System.Object 
0 
null 
0 
01/01/0001 12:00:00 a.m. 
null 

文字列の場合は、特殊なケースであるrefereceありますそれをnullにすることができ、String.Emptyの代わりにここで取得するpublicなデフォルトのコンストラクタを持たないようにします。 nullを指定できる型もnullを返します。

+0

非常に包括的な歓声! – deanvmc

2

あなたの一般的な方法にnew()制約を追加します。

public T Create<T>() where T: class, new() 
{ 
    return new T(); 
} 
3

あなたはあなたのタイプのパラメータに制約を追加することができ、それがあることから、空の引数のコンストラクタをサポートしていません任意のクラスを排除します型引数として使用されます。

public class Foo<T> where T : new() 
{ 
    // Now you can say T blah = new T(); 
} 

またActivator.CreateInstance<T>()を呼び出すことができますが、型は右のコンストラクタを持っていない場合には、スローされます。

オブジェクトが見つからない場合は、メソッドがnullを返し、呼び出しコードがその条件を適切に処理するようにすることを文書化するほうが良いかもしれないと思います。どのように進めるかを知るのが最良の立場にあるでしょう。

1

これは動作します:

using System;

public class Test 
{ 
    static T CreateT<T>(bool _new) where T: new() 
    { 
     if (_new) return new T(); else return default(T); 
    } 
    public static void Main() 
    { 
     var o = CreateT<object>(true); 
    } 
}