簡體   English   中英

在不同的類類型上創建方法

[英]Create method on different class types

我有兩節課:

 public class MyClass1 
 {
    public string AAAAA { get; set; }
    public string BBBBB { get; set; }
    public string CCCCC { get; set; }
    public string DDDDD { get; set; }
 }

 public class MyClass2 
 {
     public string AAAAA { get; set; }  // same as MyClass1 
     public string BBBBB { get; set; }  // same as MyClass1 
     public string TTTTT { get; set; }  
 }

現在我想創建這個方法:

public string PrintMe( Class1or2 obj) {
    string message = "";
    message += obj.AAAAA ;  // this parameter is in both MyClass1 and MyClass2
    message += obj.BBBBB ;  // this parameter is in both MyClass1 and MyClass2
    return message;
}

關鍵是 - 我無法觸摸MyClass1和MyClass2,因此我無法使它們使用相同的基礎。 他們是完全分開的

有什么辦法以某種方式創建這個方法,或者我會為每個類復制它?

可以選擇將方法的簽名更改為PrintMe(dynamic obj)

在編譯時它將接受任何對象,並且僅在運行時它將檢查obj實例是否實際上具有匹配的屬性。 您可以感覺到,這是非常不安全的,並且經常導致生產版本中的錯誤。

沒有其他選擇。 如果您無法更改類,但是如果您可以繼承它,則可以實現共享這些屬性的接口。 只有在您自己實際創建實例時才有效。

另一種選擇是使用包裝類:

public string PrintMe(Class1or2Wrapper obj)
{ ... }

然后,您實現了確定在哪個屬性中采用的邏輯:

public class Class1or2Wrapper
{
    private Class1 c1;
    private Class2 c2;

    public Class1or2Wrapper(Class1 c1)
    {
        this.c1 = c1;
    }

    public Class1or2Wrapper(Class2 c2)
    {
        this.c2 = c2;
    }

    public string AAAAA
    {
        get
        {
            if (this.c1 != null)
                return c1.AAAAA;

            if (this.c2 != null)
                return c2.AAAAA;

            return null;
        }
    }
}

這樣可以確保類型安全,同時限制工作量。

那么,每個類的基類都是object ,所以你可以將常見的實現隱藏為私有方法:

private string PrintMe( object obj) {
  var instance = obj is MyClass1 ? obj as MyClass1 : obj as MyClass2;

  if(instance == null)
    throw new ArgumentException("Invalid type!");

  string message = "";
  message += instance.AAAAA ;  // this parameter is in both MyClass1 and MyClass2
  message += instance.BBBBB ;  // this parameter is in both MyClass1 and MyClass2
  return message;
}

並公開公共API,這將是編譯時安全的:

public string PrintMe(MyClass1 mc)
{
  return PrintMe(mc as object);
}
public string PrintMe(MyClass2 mc)
{
  return PrintMe(mc as object);
}

或者你可以使用反射:

public static string PrintMe(object obj)
{
    string message = "";
    message += obj.GetType().GetProperty("AAAAA")?.GetValue(obj);  // this parameter is in both MyClass1 and MyClass2
    message += obj.GetType().GetProperty("BBBBB")?.GetValue(obj);    // this parameter is in both MyClass1 and MyClass2
    return message;
}

要么

public static string PrintMe(object obj, string propertyName)
{
    string message = "";
    message += obj.GetType().GetProperty(propertyName)?.GetValue(obj);
    return message;
}

在這種情況下,您不必擔心運行時異常,如果您的類具有此類屬性,它將獲取並將其值添加到message

另一種方法基於其他的答案,用干燥的一致,並且是類型安全是使內部動態/對象版本,將其標記為Obsolete (所以ditrtly小手指不使用它),並pragma就出來了警告類型安全存根。

請注意 ,這只會對面臨公眾的重載產生影響。 但是,至少如果你私下拋出一些奇怪的東西,它會給你一個警告。

[Obsolete("Warning do not use this, call blah blah blah")] 
private string InternalPrintMe(dynamic  obj)
{
     //unafe dynamic code here 
}

#pragma warning disable 0618
public string PrintMe(Class1  obj) => InternalPrintMe(obj) ;
public string PrintMe(Class2  obj) => InternalPrintMe(obj) ;
#pragma warning disable 0618

要確保AAAA,BBBB和PrintMe可用,您可以使用界面:

    public class MyClass1
    {
        public string AAAAA { get; set; }
        public string BBBBB { get; set; }
        public string CCCCC { get; set; }
        public string DDDDD { get; set; }
    }

    public class MyClass2
    {
        public string AAAAA { get; set; }  // same as MyClass1 
        public string BBBBB { get; set; }  // same as MyClass1 
        public string TTTTT { get; set; }
    }
    public static class Helper
    {
        public static string Print(IExtra obj)
        {
            string message = "";
            message += obj.AAAAA;  // this parameter is in both MyClass1 and MyClass2
            message += obj.BBBBB;  // this parameter is in both MyClass1 and MyClass2
            return message;
        }
    }
    public interface IExtra
    {
        string AAAAA { get; set; }
        string BBBBB { get; set; }
        string Print { get; }
    }
    public class MyClass1WithPrint : MyClass1, IExtra
    {
        public string Print => Helper.Print(this);
    }
    public class MyClass2WithPrint : MyClass2, IExtra
    {
        public string Print => Helper.Print(this);
    }

暫無
暫無

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

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