[英]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 個選項interface
或father class
。 Bot 2 方式需要where T: interfaceName
或where 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.