2017-08-30 70 views
0

假設我有以下interface and implementing classC#反射測試,如果成員是一個接口實現

public interface IInterface 
{ 
    string AMember { get; } 
    string OtherMember { get; } 
} 

public class Class : IInterface 
{ 

    public string OtherMember { get { return "other"; } } 

    public string AMember { get { return "class"; }} 

    string IInterface.AMember { get { return "explicit"; } } 

} 

現在,我得到通過反射的成員,想測試,如果他們是一個接口實現。

public class Program 
{ 
    public static void Main() 
    { 
     var inst = new Class(); 
     var members = typeof(Class).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); 
     foreach(var member in members) 
     { 
      object val; 
      try 
      { 
       val = member.GetValue(inst); 
      } 
      catch(MethodAccessException e) 
      { 
       val = "EXPLICIT"; 
      } 

      Console.Out.WriteLine(string.Format("{0}: {1} is interface implementation? {2}", member.Name, val, false /*member.IsInterfaceImplementation*/)); 
     } 
    } 
} 

如何測試成員是否實現了接口?

+1

我想你會以相反的方式去做。首先檢查了'Class'從接口派生,然後檢查成員 – Nkosi

+0

我想什麼是枚舉成員並檢查它是否是一個接口實現。如果接口是明確實現的,這是有問題的。 –

回答

3

如果你真的只是想檢查某個類的成員是否來自任何接口,你可以做到以下幾點:

bool myMemberComesFromInterface = typeof(Class).GetInterfaces() 
    .SelectMany(i => i.GetMember("MyMember")).Any(); 

有一個邊緣情況,但:顯式接口實現;考慮:

public interface IInterface 
{ 
    int MyMember { get; } 
} 

public class Class : IInterface 
{ 
    public string MyMember => "foo"; 
    int IInterface.MyMember => 2; 
} 

上面的代碼會產生在這種情況下true,我不能肯定,如果這是你在使用的情況下想要的。如果你不想要這個,我認爲你必須在每個接口的基礎上對你發現的成員與SelectMany(...)進行比較。也許InterfaceMapping(見here)也可以在這裏使用。

編輯:既然現在明確的是該案件很感興趣,我想擺弄的東西,會爲你的情況下工作:

var interfaces = typeof(Class).GetInterfaces() 
    .ToDictionary(i => i.FullName, i => i.GetProperties().Select(p => p.Name).ToList()); 
var properties = typeof(Class).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance); 

// explicitly implemented properties 
foreach (var pi in properties.Where(pi => pi.Name.Contains("."))) 
{ 
    Console.WriteLine($"Explicitly implemented property {pi.Name} found."); 
    var parts = pi.Name.Split('.'); 
    string interfaceName = string.Join(".", parts.Take(parts.Length - 1)); 
    string propertyName = parts[parts.Length - 1]; 
    interfaces[interfaceName].Remove(propertyName); 
} 

// rest 
foreach (var pi in properties.Where(pi => !pi.Name.Contains("."))) 
{ 
    // instead of this, you could also use LINQ and SelectMany 
    // on the Values to check for containment 
    bool found = false; 
    foreach (var interfaceName in interfaces.Keys) 
    { 
     if (interfaces[interfaceName].Contains(pi.Name)) 
     { 
      found = true; 
      Console.WriteLine($"Found property {pi.Name} in interface {interfaceName}."); 
     } 
    } 

    if (!found) 
    { 
     Console.WriteLine($"Property {pi.Name} is self-defined."); 
    } 
} 

對於你的榜樣,這給我下面的輸出:

Explicitly implemented property Fiddle.IInterface.AMember found. Found property OtherMember in interface Fiddle.IInterface. Property AMember is self-defined.

+0

是的,班級可能有明確的成員。這就是爲什麼上述解決方案在這種情況下不足的原因。 –

+0

@GerdK我會看看我是否有時間今天晚些時候檢查如何做到這一點。但是,如果您可以在原始帖子中添加/添加這些重要信息,那就太好了。 – InvisiblePanda

+0

我剛剛更新@GerdK我試圖找到一個可行的解決方案我的代碼示例 –

0

您可以使用下面的代碼:

var interfaceType = typeof(IInterface); 
var interfaceVar = typeof(Class).GetInterface(interfaceType.Name); 
var returnMethod = interfaceVar.GetMethods().FirstOrDefault(m 
     =>m.ReturnType.IsSubclassOf("MyMember") || m.ReturnType == "MyMember"); 
if(returnMethod != null){ 
    // your member is implementation of interface 
    } 
相關問題