簡體   English   中英

使用 Generics 列表時無法編譯<t>在 C#</t>

[英]Unable to compile while use the Generics List<T> in C#

我有兩個不同的課程。 而且,這兩個不同的類也有多個屬性。 考慮以下兩個示例類,

public Class1{
    public string Key;
    public string value;
}

public Class2{
    public string Key;
    public string value;
}

注意:例如,我像上面一樣添加了 class。 但是,實際上,這兩個類應該具有相同名稱的不同值。

這些類應該是如下列表的成員,

List<Class1> list1 = new List<Class1>();
List<Class2> list2 = new List<Class2>();

所以,要處理這些列表,我需要兩個不同的函數,如下所示,

private string GetStrValue(List<Class1> values)
{
    string toRet = string.Empty;
    if (values == null)
        return toRet;

    foreach (Class1 val in values)
    {
        if (!string.IsNullOrWhiteSpace(val.Key)) {
            toRet = val.value;
            break;
        }
    }

    return toRet;
}

並且,類似的 function 也可以處理 Int class。 所以,我打算使用泛型。 我已經編寫了如下代碼,

private string GetValue<T>(List<T> listValue)
{
    string toRet = string.Empty;
    if (listValue == null)
        return toRet;

    foreach (T iter in listValue)
    {
        if (!string.IsNullOrWhiteSpace(iter.Key)) {
            toRet = val.Name;
            break;
        }
    }

    return toRet;
}

但是,代碼無法編譯。 我面臨以下錯誤。

Severity    Code    Description Project File    Line    Suppression State
Error   CS1061  'T' does not contain a definition for 'Name' and no accessible extension method 'Name' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)

任何對此提供幫助的人都會非常感激。

謝謝,

您已經說過“此代碼適用於每種類型 T”,但您希望您的類型 T 有一個名為 Name 的屬性,而許多類型都沒有。 Generics 不能那樣工作。

如果你想對你的類型 T 的實例做一些需要它具有某些屬性的事情,你需要告訴編譯器 T 被限制為具有這些屬性的類型。

在您的情況下,您將需要編寫一個對兩個類都通用的接口,並將該接口添加到您的通用 T 定義中。

在此處的 Microsoft 文檔中得到了很好的解釋(包括一個很好的代碼示例)

您有 2 個選項interfacefather class Bot 2 方式需要where T: interfaceNamewhere T: fatherClassName語法

以接口為例:

public interface IClass
{
    string Key { get; set; }
    string Name { get; set; }
    string value { get; set; }
}
public class Class1 : IClass
{
    public string Key { get; set; }
    public string value { get; set; }
    public string Name { get; set; }
}

public class Class2 : IClass
{
    public string Key { get; set; }
    public string value { get; set; }
    public string Name { get; set; }
}

那么您的通用 class 將是

private string GetValue<T>(List<T> listValue) where T : IClass
{
    string toRet = string.Empty;
    if (listValue == null)
        return toRet;

    foreach (T val in listValue)
    {
        if (!string.IsNullOrWhiteSpace(val.Key))
        {
            toRet = val.Name;
            break;
        }
    }

    return toRet;
}

您可以使用 Reflection 使其完全通用(請參閱Reflection | PropertyInfo )。 這樣,您將能夠處理任何給您上課的課程。 請參考下面的示例代碼:

private string GetValue<T>(List<T> listValue)
{
    string toRet = string.Empty;
    if (listValue == null)
        return toRet;
    PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

    //Since you have mentioned all classes will have "Key" and "Value" and you need to use that only
    //To make it completely generic you can maybe get this as input to this function

    PropertyInfo keyProperty = properties.FirstOrDefault(x => x.Name.Equals("Key", StringComparison.OrdinalIgnoreCase));
    PropertyInfo valueProperty = properties.FirstOrDefault(x => x.Name.Equals("Value", StringComparison.OrdinalIgnoreCase));

    if (keyProperty == null || valueProperty == null)
        return toRet;

    foreach (T iter in listValue)
    {
        var keyData = keyProperty.GetValue(iter, null);
        if (keyData != null && !string.IsNullOrWhiteSpace(keyData.ToString()))
        {
            toRet = valueProperty.GetValue(iter, null).ToString();
            break;
        }
    }

    return toRet;
}

正如nvoigt提到的,在這種情況下我們必須使用“接口”概念。

定義你的類和接口如下:

public interface IKeyValue
{
    public string Key { get; set; }
    public string Value { get; set; }
}

public class A : IKeyValue
{
    public string Key { get; set; }
    public string Value { get; set; }
    //other properties... 
}

public class B : IKeyValue
{
    public string Key { get; set; }
    public string Value { get; set; }
    //other properties...
}

你的方法將使用'Key'和'Value'應該是這樣的:

    private string GetValue<T>(List<T> listValue) where T: IKeyValue
    {
        string toRet = string.Empty;
        if (listValue == null)
            return toRet;

        foreach (T iter in listValue)
        {
            if (!string.IsNullOrWhiteSpace(iter.Key))
            {
                toRet = iter.Value;
                break;
            }
        }

        return toRet;
    }

方法定義中的“其中 T:IKeyValue”表示類型 T 是“ IKeyValue ”,這導致我可以在上下文中訪問“ Key ”和“ Value ”(僅在IKeyValue接口中的那些)

這是您可以使用它的方式:

        List<IKeyValue> keyValues = new List<IKeyValue>
        {new A{Key="a",Value="b"}, new B{Key="x",Value="y"}};

        List<A> listA = new List<A> 
        { new A { Key = "h", Value = "b" }, new A { Key = "u", Value = "m" } };

        List<B> listB = new List<B> 
        { new B { Key = "h", Value = "b" }, new B { Key = "u", Value = "m" } };

        string resultListInterface = GetValue(keyValues); //valid
        string resultListA = GetValue(listA);             //valid
        string resultListB = GetValue(listB);             //valid

對於命名約定,我將屬性名稱從“”更改為“

暫無
暫無

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

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