0

この C# WinForms コードには、いくつかの異なるstructsがあり、すべて同じように機能します。そのため、アイテムを追加または削除するための個々の関数を記述する代わりに、代わりにテンプレートを使用しようとしています。

たとえば、これは1つと、その保存に使用してstructいる対応するものです:List<>objects

public struct Alias
{
    public string alias;
    public string aliasSource;

    public static bool IsValid(...); //This function exists in all the structs
};

List<Alias> aliases;

これは、エイリアスを追加するために外部から使用される関数です。

public void AddAlias(Alias iAlias)
{
    AddGenericStructItem<Alias>(iAlias, aliases);
}

そして、これは加算を行う実際の関数です:

private void AddGenericStructItem<T>(T genericStructItem, List<T> genericList)
{
    string outputError;
    if (T.IsValid(genericStructItem, out outputError)) //< -- Problem in the 'T' being used in the far left
    {
        if (genericList.Contains(genericStructItem))
        {
            MessageBox.Show("ERROR 82ha5jb :: Item already exists");
        }
        else
        {
            genericList.Add(genericStructItem);
        }
    }
    else
    {
        MessageBox.Show(outputError);
    }
}

部品で問題が発生しT.IsValid...ます。コンパイラは、次のエラーを表示しますT

'T' is a 'type parameter', which is not valid in the given context

これを回避する方法はありますか?私はすべて同じ設定で関数をstructs持っているIsValidので、ここでテンプレートを使用しない場合、同じコードを繰り返し書くのはばかげているように思えます...

4

3 に答える 3

2

あなたはそれをすることはできません。唯一のオプションはwhere、ジェネリックパラメーターの制約を何らかのインターフェイスまたは基本クラスタイプに定義することです。ただし、構造体でも静的メンバーでもこれを行うことはできません。構造体をクラスに変更すると、次のことができます。

public interface IValidatable
{
   bool IsValid(out outputError);
}

public class Alias : IValidatable
{
    public string alias;
    public string aliasSource;

    public bool IsValid(out outputError) { ... };
};

これで、制約を適用できます。

private void AddValidatableItem<T>(T item, List<T> list)
   where T : IValidatable
{
    string outputError;
    if (!item.IsValid(out outputError))
    {
        MessageBox.Show(outputError);
        return;
    }

    if (list.Contains(item))
    {
        MessageBox.Show("ERROR 82ha5jb :: Item already exists");
        return;
    }

    list.Add(item);       
}

ところで、C#拡張メソッドを利用して、このメソッドを検証可能なアイテムリストの拡張にすることができます。

public static void AddValidatableItem<T>(this List<T> list, T item)
    where T : IValidatable

これにより、リストのメソッドを呼び出すことができます。

aliases.AddValidatableItem(newAlias);
于 2013-02-05T16:49:06.480 に答える
0

構文は似ていますが、C#ジェネリックはC++のテンプレートとは大きく異なります。

あなたが言う時

T.IsValid(genericStructItem, out outputError);

コンパイラがあなたに代用Tすることを期待しているようAliasです

Alias.IsValid(genericStructItem, out outputError);

これはジェネリックがどのように機能するかではありません。IsValidリフレクションや構造体への共通インターフェースの追加など、別の呼び出し方法を見つける必要があります。

また、構造体の代わりにクラスを使用することを強く検討します。構造体を選択する理由はわかりませんが、特に可変である必要がある場合は、一般に構造体を使用しない理由がいくつかあります。

于 2013-02-05T17:01:58.440 に答える
0

制約を使用して、静的メソッドがオブジェクトに存在することをコンパイラに伝えることはできません。本当に静的にする必要がある場合は、リフレクションを使用してメソッドを呼び出す必要があります。

var methodInfo = typeof(T).GetMethod("IsValid", BindingFlags.Static|BindingFlags.Public);
if (methodInfo != null)
{
    object[] parameters = new object[] { genericStructItem, null };
    if ((bool)methodInfo.Invoke(null, parameters))
    {
        // It's valid!
    }
    else
    {
        string error = (string)parameters[1];
    }
}
于 2013-02-05T16:51:42.563 に答える