在不同的类类型上创建方法

时间:2019-06-11 06:59:36

标签: c# 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 ,因此我无法使它们使用相同的基准。它们完全分开

是否可以通过某种方式创建此方法,或者我将为每个类重复创建此方法?

5 个答案:

答案 0 :(得分:8)

有一个方法可以将方法的签名更改为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;
        }
    }
}

这样,您可以在限制工作量的同时确保类型安全。

答案 1 :(得分:3)

好吧,每个类的基类都是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);
}

答案 2 :(得分:0)

或者您可以使用反射:

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

答案 3 :(得分:0)

根据其他答案进行操作,保持DRY并保持类型安全的另一种方法是制作内部动态/对象版本,将其标记为Obsolete(因此,小手指不要使用它) ,并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

答案 4 :(得分:0)

要确保可以使用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);
    }