2013-07-23 10 views
21

私はこの一般的な方法を単純化するために作成しようとしていますが、私はそれを台無しにしたと思います!私の問題を助けてくれますか?複数のクラスを持つ汎用

これはコンパイル:

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Supplier, new() 
    where T1 : Employee, new() 
    where T2 : SupplierDepartment, new() 
    where T2 : EmployeeDepartment, new() 
{ 
    T1 p = new T1(); 
    T2 r = new T2(); 
    //Code here for myEntity treatment 
    return mystring; 
} 

をこれがコンパイルされていませんが:

protected void mybutton1_Click(object sender, EventArgs e) 
{ 
    string mystring = ConcatenaText<Supplier, SupplierDepartment>(myEntity); 
} 

//This does not compile 
protected void mybutton2_Click(object sender, EventArgs e) 
{ 
    string mystring = ConcatenaText<Employee, EmployeeDepartment>(myEntity); 
} 

メッセージ:タイプサプライヤーがジェネリック型またはメソッドConcatenateTextタイプパラメータT1として使用することができない(MyEntity myEntity )。サプライヤから従業員への暗黙的な参照変換はありません

これを行うことはできますか?私は間違って何をしていますか?それは改善することができますか?

EDIT:

そしてMyEntityこのジェネリックメソッドの内部でそれを処理するために、ちょうど別のクラスです!これはT型には関係しません。単なる引数です。しかし、私はそれを行うことができないことは明らかです。そのような2つのタイプを使用します。私は私が1つまたは別のものを割り当てることができると思っていました。私の初期設定から独立したCLRは、私が望むように反応しました。私はそれについてもう少し情報を共有する答えを受け入れるつもりです。

答えて

24

まず、上の2つのタイプの制約を設定しようとするあなたのコード汎用パラメータT1はコンパイルされません

where T1 : Supplier, new() 
where T1 : Employee, new() 
次のエラーと

A constraint clause has already been specified for type parameter 'T1'. All of the constraints for a type parameter must be specified in a single where clause.

MSDNの記事では、各ジェネリックパラメータ(http://msdn.microsoft.com/en-us/library/bb384067.aspxを参照)に一つだけwhere制約を使用することができます述べています。

"With multiple type parameters, use one where clause for each type parameter..."

「場所」制約に複数のクラス名を入れることもできません。 1つのクラス名と複数のインターフェイスのみ。

where T1 : Supplier, IContractor, IComparable, new() 

この制約は、ジェネリックパラメータT1としてあなたが提供する実際の型は、サプライヤークラスまたはサプライヤークラス自体の後継者でなければならず、それは両方のIContractorIComparableインタフェースを実装する必要があること。決定づけることに留意してください

メソッドがMyEntityオブジェクトを受け取り、EmployeeクラスとSupplierクラスにどのような関係があるかを指定しないと、このMyEntityクラスがEmployeeクラスとSupplierクラスをどのように知っているか、この関係がどのように役立つかは推測できません。

私が示唆できるのは、インターフェイスまたはベースクラスを作成し、そこから両方のクラスを継承することだけです。これは、一般的なメソッドを作成するために私が見る唯一の良い理由です。あなたのクラスのサプライヤーと従業員は、彼らはあなたがそれらを処理するための汎用的な方法を行うべきではありません実装することができ、共通のインタフェースを作成するために十分である共通で重要な何かを持っていない場合は

class Program 
{ 
    static void Main(string[] args) 
    { 
     Method1<Employee>(); 
     Method1<Supplier>(); 
    } 

    private static void Method1<T1>() 
     where T1 : IContractor, new() 
    { 

    } 
} 

public class Supplier : IContractor 
{ 
    string IContractor.Name 
    { 
     get{return "Supplier-Mufflier";} 
    } 
} 

public class Employee : IContractor 
{ 
    string IContractor.Name 
    { 
     get{return "Employee-Merloyee";} 
    } 
} 

public interface IContractor 
{ 
    string Name 
    { 
     get; 
    } 
} 

:それはこのようになります。

このような型ごとにオーバーロードされたメソッドを作成します。

WifeWineの2つのクラスがあるとします。両方とも属性がAgeで、同じタイプのものもあります。しかし、それらのクラスのために共通のインタフェースIAgedを作成することについて考えることさえしないでください。 Ageのクラスと意味の本質は非常に異なり、決して統一するべきではありません。それにもかかわらず、いくつかの共通ロジックが完全にあなたに役立つかもしれません。例えば:私は私の答えを書いていた一方で

private double AgeQualify(Wife someWife) 
{ 
    return 1/(someWife.Age * someWife.Beachness); 
} 

private double AgeQualify(Wine someWine) 
{ 
    return someWine.Age/someWine.Sugar; 
} 
+0

おっとは、他の二人は登場し、ほぼ同じ –

+0

偉大な答えを言ったが、私は正確に覚えていた場合、あなたは1クラス上の複数のクラスをオーバーロードすることはできません。インターフェイスとジェネリックはこの例では良い選択です。 –

+1

@TarıközgünGünerオーバーロードとオーバーライドを混同しないでください。 –

8

あなたはどちらか、別のバージョンにする必要があります。

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Supplier, new() 
    where T2 : SupplierDepartment, new() 
{ 
    T1 p = new T1(); 
    T2 r = new T2(); 
    return mystring; 
} 

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Employee, new() 
    where T2 : EmployeeDepartment, new() 
{ 
    T1 p = new T1(); 
    T2 r = new T2(); 
    return mystring; 
} 

またはそれらをベースクラスを共有行う必要があります。

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : EmployeeSuplierBase, new() 
    where T2 : EmployeeSupplierDeparmentBase, new() 
{ 
    T1 p = new T1(); 
    T2 r = new T2(); 
    return mystring; 
} 

は、私は、彼らがために彼らと、本当に、別のバージョンを好みますSupplierEmployeeDeparmentで呼び出すことはできません(またはその逆)

2

実際にはジェネリックを使用しないでください。 2つのオプションしかありません。

ので:あなたは何ができるか

string ConcatenateText(Supplier Entity) { ...code...} 
string ConcatenateText(Employee Entity) { ...code...} 

は、すべての一般的な方法を集中し、基本クラスの両方を統一です。

言って、サプライヤーと従業員の双方がNameを持っている場合:

class BaseClass 
{ 
    public string Name {get; set;} 
} 

class Employee : BaseClass 
{ 
    //emplyee stuff except name and other things already in base 
} 

class Supplier : BaseClass 
{ 
    //supplier stuff except name and other things already in base 
} 

そして、この方法は、BaseClassを取る:すべての

private string ConcatenateText(BaseClass Entity) 
{ 
    //code 
}