簡體   English   中英

通用構造函數和反射

[英]Generic constructors and reflection

是否有可能看到哪個構造函數是通用構造函數?

internal class Foo<T>
{
  public Foo( T value ) {}
  public Foo( string value ) {}
}

var constructors = typeof( Foo<string> ).GetConstructors();

屬性'ContainsGenericParameters'返回兩個構造函數false。 有沒有辦法找出構造函數[0]是通用的? 它們都有相同的簽名,但我想稱之為“真正的”字符串。

編輯:

我想使用調用給定的類型

ilGen.Emit( OpCodes.Newobj, constructorInfo );

所以我需要使用綁定版本。 但我想調用“最好的”構造函數。 這應該是標准行為。 我打電話的時候

new Foo<string>()

調用帶有字符串簽名的構造函數(而不是具有通用簽名的構造函數)。 我的代碼也應該這樣。

您需要System.Reflection.ParameterInfo.ParameterType.IsGenericParameter。 這是一個通過的VS2008單元測試,說明了這一點:

類:

public class Foo<T>
{
    public Foo(T val)
    {
        this.Value = val.ToString();
    }
    public Foo(string val)
    {
        this.Value = "--" + val + "--";
    }

    public string Value { get; set; }
}

測試方法:

Foo<string> f = new Foo<string>("hello");
Assert.AreEqual("--hello--", f.Value);

Foo<int> g = new Foo<int>(10);
Assert.AreEqual("10", g.Value);

Type t = typeof(Foo<string>);
t = t.GetGenericTypeDefinition();

Assert.AreEqual(2, t.GetConstructors().Length);

System.Reflection.ConstructorInfo c = t.GetConstructors()[0];
System.Reflection.ParameterInfo[] parms = c.GetParameters();
Assert.AreEqual(1, parms.Length);
Assert.IsTrue(parms[0].ParameterType.IsGenericParameter);

c = t.GetConstructors()[1];
parms = c.GetParameters();
Assert.AreEqual(1, parms.Length);
Assert.IsFalse(parms[0].ParameterType.IsGenericParameter);

這里值得注意的是parms [0] .ParameterType.IsGenericParameter檢查,它檢查參數是否是泛型。

一旦找到了構造函數,就可以將ConstructorInfo傳遞給Emit。

public System.Reflection.ConstructorInfo FindStringConstructor(Type t)
{
    Type t2 = t.GetGenericTypeDefinition();

    System.Reflection.ConstructorInfo[] cs = t2.GetConstructors();
    for (int i = 0; i < cs.Length; i++)
    {
        if (cs[i].GetParameters()[0].ParameterType == typeof(string))
        {
            return t.GetConstructors()[i];
        }
    }

    return null;
}

不完全確定你的意圖是什么。

稍作澄清。 兩個構造函數都不是通用方法。 它們是泛型類的常規方法。 對於“通用”方法,它必須具有通用參數。 因此,像“IsGenericMethod”這樣的測試將返回false。

簡單地查看參數並確定它們是否通用也不容易。 對於您提供的示例,可以遍歷參數並查找泛型參數。 但也要考慮以下代碼

public Foo(IEnumerable<T> p1) ...
public Foo(IEnumerable<KeyValuePair<string,Func<T>>> p1) ...

您需要考慮這樣的項目。

編輯

您將所有參數視為字符串的原因是因為您在獲取構造函數之前顯式綁定了類型Foo。 嘗試將代碼切換為使用未綁定Foo的以下代碼,因此將返回方法中的泛型參數。

var constructors = typeof( Foo<> ).GetConstructors();

您可以檢查Type.GetGenericArguments結果類型,並將其與構造函數參數類型進行比較。

只需調用類型不一樣的類型(類型!= typeof(T))。

當你說你想要調用具體的構造函數時,你能解釋一下你想要完成的事情嗎? 我只是好奇是否有另一種方法可以解決您的問題,而無需檢測構造函數是否包含泛型參數。

我正在考慮將構造函數或構建邏輯鏈接到通用構造函數中,如果傳入的參數是字符串,則表現為某種方式,例如:

    static void Main(string[] args)
    {
        Console.WriteLine(new Foo<string>("myValue").IsValueAString);
        Console.WriteLine(new Foo<int>(1).IsValueAString);
        Console.ReadLine();
    }

    public class Foo<T>
    {
        public bool IsValueAString = false;
        public Foo(T value) {
            if (value is string)
            {
                IsValueAString = true;
            }
        }
    }

另一個選擇是創建Foo的具體實現,如:

internal class Foo<T>
{
    ...
}
internal class MyFoo : Foo<string>
{
    ...
}

並在后代的構造函數中嵌入任何特定的邏輯。 這條路徑上的各種選項都是可能的,因此您可以避免必須反映該類的信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM